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,315 @@
# 数据导入
<cite>
**本文引用的文件**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
- [IOManager.h](file://h/IOManager.h)
- [Constant.h](file://h/Constant.h)
- [DataOperator.h](file://h/DataOperator.h)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
## 简介
本文件面向“数据导入”功能的完整流程进行深入文档化,重点覆盖:
- CIOManager::Import 方法如何验证源.accdb文件的有效性(数据库版本检查、密码验证机制)
- 导入过程中的事务管理与数据一致性保障
- ImportProjectToDB、ImportTzToDB 等系列方法如何解析外部数据库并安全导入到当前系统数据库
- 数据映射规则、主键处理、外键约束维护及冲突解决策略
- 导入失败时的回滚机制与错误报告方式
## 项目结构
数据导入功能位于 Managers 层,核心类为 CIOManager,负责导入与导出的统一入口;导入流程围绕 Access 数据库(.accdb)展开,使用 ADO/ADOX 进行连接与表结构创建,并通过事务保证一致性。
```mermaid
graph TB
subgraph "导入模块"
CIO["CIOManager<br/>导入/导出入口"]
Imp["Import()<br/>验证与事务控制"]
Proj["ImportProjectToDB()"]
Tz["ImportTzToDB()"]
Spt["ImportSptToDB()"]
Rsp["ImportRspTdToDB()"]
Ipsp["ImportIpspTdToDB()"]
end
subgraph "系统数据库"
SysConn["_ConnectionPtr<br/>系统数据库连接"]
Cat["ADOX::Catalog<br/>表结构管理"]
end
subgraph "外部数据库(.accdb)"
ExtConn["_ConnectionPtr<br/>外部数据库连接"]
DbVer["dbversion 表<br/>版本校验"]
end
CIO --> Imp
Imp --> Proj
Imp --> Tz
Imp --> Spt
Imp --> Rsp
Imp --> Ipsp
Imp --> SysConn
CIO --> Cat
Imp --> ExtConn
ExtConn --> DbVer
```
图表来源
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L100-L204)
- [IOManager.h](file://h/IOManager.h#L15-L51)
章节来源
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L100-L204)
- [IOManager.h](file://h/IOManager.h#L15-L51)
## 核心组件
- CIOManager:导入/导出的统一入口,提供 Import/Export 方法,内部封装对各业务表的导入逻辑。
- 外部数据库(.accdb):包含 project、tz、td、tdhead、parameter、rspcon、ipspcon、gr、scon、channel、script、dbversion 等表。
- 系统数据库:通过 ADOX 创建目标表结构,使用 ADO 执行插入与更新。
- 常量与返回码:统一的执行状态码(成功/失败/取消/重复/关联异常等),用于错误上报与流程控制。
章节来源
- [IOManager.h](file://h/IOManager.h#L15-L51)
- [Constant.h](file://h/Constant.h#L138-L151)
## 架构总览
导入流程采用“打开外部数据库 -> 版本校验 -> 开启系统数据库事务 -> 分表导入 -> 提交或回滚”的模式。每个导入方法均以“先查询是否存在同名记录 -> 若不存在则插入 -> 存在则跳过(去重)”的策略避免重复导入;同时通过外键字段(如 PRID、TZID、PAID、SCID、DEID、TDID)将不同表之间的关系映射到系统数据库。
```mermaid
sequenceDiagram
participant U as "用户"
participant M as "CIOManager"
participant E as "外部数据库(.accdb)"
participant S as "系统数据库"
participant T as "事务"
U->>M : 调用 Import()
M->>E : 打开外部数据库并设置密码
M->>E : 查询 dbversion 表进行版本校验
alt 校验失败
M-->>U : 返回取消/失败
else 校验成功
M->>S : BeginTrans()
M->>S : 导入 project
M->>S : 导入 tz
M->>S : 导入 scon/channel/script
M->>S : 导入 td/rspcon/ipspcon/gr
alt 导入过程中发生异常
M->>S : RollbackTrans()
M-->>U : 返回失败
else 成功
M->>S : CommitTrans()
M-->>U : 返回成功
end
end
```
图表来源
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L100-L204)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1960-L2064)
## 详细组件分析
### CIOManager::Import 验证与事务控制
- 文件选择与连接
- 弹出文件对话框选择 .accdb 文件,构造连接字符串并设置数据库密码。
- 设置最大锁数属性以提升并发写入能力。
- 版本检查
- 通过查询外部数据库的 dbversion 表,要求存在特定键值(版本标识)才视为有效外部数据库。
- 若未命中或抛出异常,关闭连接并提示错误后返回取消/失败。
- 事务管理
- 成功通过版本检查后,开启系统数据库事务。
- 按顺序调用 ImportProjectToDB、ImportTzToDB、ImportSptToDB、ImportRspTdToDB、ImportIpspTdToDB。
- 成功则提交,失败则回滚并返回失败。
章节来源
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L100-L204)
### ImportProjectToDB:工程表导入
- 映射字段
- 将外部 project 的 CN、PRname、PRdesc、location、PRdate、duration、PS、CS、PM、QAS、standard 映射到系统 project。
- 冲突处理
- 先按 CN 查询系统 project 是否已存在,若不存在则插入;存在则跳过。
- 主键/唯一性
- 以 CN 作为唯一键进行去重判断。
章节来源
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L2013-L2062)
### ImportTzToDB:测区表导入
- 映射字段
- 外部 tz 的 TZname、PRCN、TZdesc、location 映射到系统 tz。
- 关系解析
- 通过外部 tz.PRCN 查找系统 project 的 IDPRID),再以 PRID+TZname 在系统 tz 中查重。
- 冲突处理
- 若系统 tz 中不存在相同 PRID+TZname,则插入;否则跳过。
章节来源
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1960-L2011)
### ImportSptToDB:脚本与通道导入
- 映射字段
- 外部 scon 的 CN、Sname、Eamount、CHamount、TPamount、definer、DEdate、SCdesc 映射到系统 scon。
- 外部 channel 的 CN、CHnumber、AR 映射到系统 channel(通过 SCID 关联 scon)。
- 外部 script2d 的 CN、CHnumber、TSN、C1、C2、P1、P2、K、N 映射到系统 script2d(通过 CHID 关联 channel)。
- 冲突处理
- scon:按 CN 去重;插入后获取新 ID(SCID)。
- channel:按 CN+CHnumber 去重;插入后获取新 IDCHID)。
- script2d:按 CN+CHnumber+TSN 去重;插入时使用 CHID。
- 外键维护
- td 表导入完成后,根据外部 SCCN 更新 td.SCID 字段,完成脚本与测线的关联。
章节来源
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1385-L1519)
### ImportRspTdToDB:电阻率测线导入
- 映射字段
- 外部 td 的 TDname、DESN、PRCN、TZname、SCCN、TDtype、HFname、CFname、CFRamount、GRFname、GRFRamount 映射到系统 td。
- 外部 tdhead 的 TDname、DESN、Cdate、Ctime、rolling、RCamount、Rdirection、CRtime、CPE、CPN、weather、temperature、height、humidity、PM、OP、QA 映射到系统 tdhead。
- 外部 parameter 的 TDname、DESN 对应的 LCHamount、RCHamount、LCamount、RCamount、LEamount、REamount、Felectrode、Espacing、Clayout、CLfun 映射到系统 parameter。
- 外部 rspcon 的 TDname、DESN 对应的 A、B、M、N、K、SP、Ro、Vp、Ip、SD、RgA、RgB、RgM、RgN、Ttime 映射到系统 rspcon。
- 外部 gr 的 TDname、DESN 对应的 electrode、CableH、CableT、P1GR、P2GR 映射到系统 gr。
- 关系解析
- 通过 PRCN 获取 PRID,再通过 PRID+TZname 获取 TZID。
- 通过 DESN 获取 DEID(设备 ID),若不存在则置为 0。
- 通过 SCCN 获取 SCID,若不存在则置为 0。
- 插入 parameter 后获取 PAID;插入 td 后获取 TDID;随后插入 rspcon/gr 使用 TDID。
- 冲突处理
- td:按 TDname+DESN 去重;不存在则插入并生成 TDID。
- rspcon/gr:按 TDname+DESN+时间戳(或唯一组合)去重;不存在则插入。
- 外键维护
- 通过 PRID、TZID、PAID、SCID、DEID、TDID 维护层级关系。
章节来源
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1743-L1957)
### ImportIpspTdToDB:激电测线导入
- 映射字段
- 与电阻率测线类似,但映射到系统 rspcon 的字段为 SP、Ro、VP、IP、M1..M7、TH、D、Zp、FG、Am、Bm、Cm、Dm、r。
- 关系解析与冲突处理
- 同样基于 PRCN->PRID、PRID+TZname->TZID、DESN->DEID、SCCN->SCID、TDname+DESN->TDID 的映射链路。
- 以 TDname+DESN 去重插入 td;随后按 TDname+DESN+唯一字段去重插入 rspcon/gr。
章节来源
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1521-L1741)
### 数据映射规则与主键/外键处理
- 映射规则
- 外部表字段与系统表字段一一对应,部分日期/数值类型在插入前进行格式化或空值处理。
- 外部表中的“编号”字段(如 CN、PRCN、SCCN、DESN)作为跨表关联与去重的关键键。
- 主键处理
- 系统侧通过自增主键(如 scon.ID、channel.ID、script2d.ID、td.ID、parameter.ID)生成并维护。
- 外部侧以 CN、PRCN、SCCN、DESN 等作为唯一键进行去重。
- 外键约束维护
- 通过 PRCN->PRID、PRID+TZname->TZID、DESN->DEID、SCCN->SCID、TDname+DESN->TDID 等映射,确保 td、rspcon、gr、parameter 等表的外键字段正确指向父表。
- 冲突解决策略
- 优先采用“存在即跳过”的策略,避免重复导入导致的数据冗余与索引冲突。
- 对于脚本与测线的二次关联(如 td.SCID 的更新),在导入 scon 后统一执行,确保外键完整性。
章节来源
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1385-L1519)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1521-L1957)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L2013-L2062)
### 事务管理与一致性保障
- 事务边界
- 在 Import() 中开启系统数据库事务,随后依次导入各表;任一环节失败均触发回滚。
- 错误传播
- 导入过程中捕获 COM 错误并返回失败码;UI 层根据返回码进行提示与后续处理。
- 并发与锁
- 外部数据库连接设置最大锁数,减少锁竞争带来的写入阻塞。
章节来源
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L100-L204)
### 导入失败的回滚与错误报告
- 回滚机制
- 导入任一阶段抛错,立即回滚系统数据库事务并关闭外部数据库连接。
- 错误报告
- 通过统一的状态码(成功/失败/取消/重复/关联异常等)向调用方反馈结果。
- UI 层根据状态码弹出提示或进入错误处理流程。
章节来源
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L100-L204)
- [Constant.h](file://h/Constant.h#L138-L151)
## 依赖关系分析
- CIOManager 依赖系统数据库连接与 ADOX Catalog,用于创建目标表结构与执行插入。
- 导入方法之间存在强依赖顺序:project -> tz -> scon/channel/script -> td/rspcon/ipspcon/gr。
- 外部数据库必须包含 dbversion 表且包含特定键值,否则导入被拒绝。
```mermaid
classDiagram
class CIOManager {
+Import() uint
+Export() uint
-ImportProjectToDB(pImp)
-ImportTzToDB(pImp)
-ImportSptToDB(pImp)
-ImportRspTdToDB(pImp)
-ImportIpspTdToDB(pImp)
-m_pConnection
-m_pCatalog
}
class Constant {
+APP_SUCCESS
+APP_FAIL
+APP_CANCLE
+APP_DUPLICATE
+APP_RELATION
+APP_OVERFLOW
+APP_DEFAULT
}
CIOManager --> Constant : "使用返回码"
```
图表来源
- [IOManager.h](file://h/IOManager.h#L15-L51)
- [Constant.h](file://h/Constant.h#L138-L151)
章节来源
- [IOManager.h](file://h/IOManager.h#L15-L51)
- [Constant.h](file://h/Constant.h#L138-L151)
## 性能考量
- 外部数据库写入优化
- 在导入前设置最大锁数,降低锁竞争,提高批量写入效率。
- 查询与去重策略
- 通过唯一键(CN、PRCN、SCCN、DESN、TDname+DESN 等)进行去重,避免重复插入。
- 事务粒度
- 将所有导入步骤置于同一事务内,减少中间态,保证一致性的同时也意味着单次失败需整体回滚。
- I/O 与网络
- .accdb 文件通常本地存储,性能瓶颈主要在数据库写入与索引构建;建议在导入前关闭不必要的 UI 刷新与日志输出。
[本节为通用性能建议,不直接分析具体文件]
## 故障排查指南
- 常见问题与定位
- 外部数据库无法打开或密码错误:检查连接字符串与密码设置;确认 .accdb 文件未损坏。
- 版本校验失败:确认外部数据库包含 dbversion 表且包含指定键值。
- 导入失败回滚:查看返回码与异常栈,定位具体导入方法;检查唯一键冲突与外键映射是否正确。
- 建议排查步骤
- 独立运行 ImportProjectToDB/ImportTzToDB,确认基础表导入成功。
- 检查 scon/channel/script 的关联是否正确,必要时手动执行 td.SCID 更新。
- 对照外部与系统表结构,核对字段映射与空值处理逻辑。
章节来源
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L100-L204)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1385-L1519)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1521-L1957)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1960-L2062)
## 结论
本导入流程通过严格的版本校验、事务控制与去重策略,实现了从外部 .accdb 到系统数据库的可靠迁移。其关键特性包括:
- 明确的验证与错误处理路径
- 以唯一键驱动的去重与外键映射
- 事务边界内的原子性与一致性
- 清晰的失败回滚与状态码反馈
在实际部署中,建议结合业务场景对字段映射与去重策略进行微调,并在导入前做好备份与测试,以确保数据完整性与可追溯性。
@@ -0,0 +1,293 @@
# 数据导入导出
<cite>
**本文档引用的文件**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
- [IOManager.h](file://h/IOManager.h)
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp)
- [HandleProcessor.cpp](file://cpp/Tools/HandleProcessor.cpp)
- [StateProcessor.cpp](file://cpp/Tools/StateProcessor.cpp)
- [FileTransfer.h](file://h/FileTransfer.h)
- [_zmodem.h](file://h/_zmodem.h)
</cite>
## 目录
1. [简介](#简介)
2. [CIOManager类架构](#ciomanager类架构)
3. [数据导出功能](#数据导出功能)
4. [数据导入功能](#数据导入功能)
5. [文件传输协议](#文件传输协议)
6. [数据完整性与事务处理](#数据完整性与事务处理)
7. [应用场景分析](#应用场景分析)
8. [结论](#结论)
## 简介
数据导入导出模块是Geomative Studio系统中的核心功能组件,负责实现项目数据在不同环境间的迁移与共享。该模块主要通过CIOManager类实现,支持将项目、测区、脚本、测试数据等关键信息导出为Access数据库(.accdb)文件,并能从外部文件导入数据。模块采用事务处理机制确保数据一致性,通过Zmodem协议支持串口和网络数据交换,为系统升级、数据迁移等场景提供可靠支持。
## CIOManager类架构
CIOManager类是数据导入导出功能的核心实现,其架构设计体现了清晰的职责分离和模块化思想。该类主要负责协调数据导出和导入流程,与数据库交互,并管理相关辅助组件。
```mermaid
classDiagram
class CIOManager {
+_ConnectionPtr m_pConnection
+ADOX : : _CatalogPtr m_pCatalog
+CHandleProcessor m_handleProcessor
+CStateProcessor m_stateProcessor
+UINT Export()
+UINT Import()
-_ConnectionPtr CreateExpDatabase(CString szFileName)
-void ExportDataToAccdbFile(_ConnectionPtr pExpConnection, CTreeCtrl& dmsTree)
-void ImportProjectToDB(_ConnectionPtr pImpConnection)
}
class CHandleProcessor {
+DWORD GenerateHandle(DWORD dwID, UINT uStyle)
+DWORD GetIDFromHandle(DWORD dwHandle)
+UINT GetStyleFromHandle(DWORD dwHandle)
+void AnalyseHandle(DWORD dwHandle, DWORD& dwID, UINT& uStyle)
}
class CStateProcessor {
+UINT ChangeToImageState(UINT uItemState)
+UINT ChangeToItemState(UINT uImageState)
}
CIOManager --> CHandleProcessor : "使用"
CIOManager --> CStateProcessor : "使用"
```
**图示来源**
- [IOManager.h](file://h/IOManager.h#L15-L49)
- [HandleProcessor.cpp](file://cpp/Tools/HandleProcessor.cpp#L19-L95)
- [StateProcessor.cpp](file://cpp/Tools/StateProcessor.cpp#L19-L40)
**本节来源**
- [IOManager.h](file://h/IOManager.h#L15-L49)
- [HandleProcessor.cpp](file://cpp/Tools/HandleProcessor.cpp#L19-L95)
- [StateProcessor.cpp](file://cpp/Tools/StateProcessor.cpp#L19-L40)
## 数据导出功能
数据导出功能通过CIOManager::Export()方法实现,采用事务处理机制确保数据完整性。导出流程首先创建新的Access数据库文件,然后按层次结构导出项目、测区、测试数据和脚本信息。
### 导出工作流程
```mermaid
flowchart TD
Start([开始导出]) --> CreateDialog["创建导出对话框"]
CreateDialog --> ShowDialog["显示导出界面"]
ShowDialog --> UserSelect["用户选择导出内容"]
UserSelect --> CheckSelection{"选择有效?"}
CheckSelection --> |否| ReturnCancel["返回取消"]
CheckSelection --> |是| CreateDatabase["创建目标数据库"]
CreateDatabase --> BeginTrans["开始事务"]
BeginTrans --> ExportProject["导出项目信息"]
ExportProject --> ExportTz["导出测区信息"]
ExportTz --> ExportTd["导出测试数据"]
ExportTd --> ExportSpt["导出脚本信息"]
ExportSpt --> CommitTrans["提交事务"]
CommitTrans --> CloseDB["关闭数据库连接"]
CloseDB --> ReturnSuccess["返回成功"]
Exception["异常捕获"] --> RollbackTrans["回滚事务"]
RollbackTrans --> DeleteFile["删除目标文件"]
DeleteFile --> ReturnFail["返回失败"]
CreateDatabase --> |失败| DeleteFile
style Exception fill:#f9f,stroke:#333,stroke-width:2px
```
**图示来源**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L35-L98)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L657-L656)
**本节来源**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L35-L98)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L657-L656)
### 不同数据类型的导出策略
系统针对不同类型的数据采用了差异化的导出策略:
| 数据类型 | 导出策略 | 相关方法 |
|---------|---------|---------|
| 项目数据 | 导出项目基本信息、描述、位置等 | ExportProjectToAccdbFile |
| 测区数据 | 导出测区名称、描述、位置等,并关联项目 | ExportTzToAccdbFile |
| 测试数据 | 根据测试类型(RSP/IPSP)分别导出,包含测试头信息和参数 | ExportRspTdToAccdbFile<br>ExportIpspTdToAccdbFile |
| 脚本数据 | 导出脚本定义、通道配置和脚本内容 | ExportSptToAccdbFile |
**本节来源**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L894-L1383)
## 数据导入功能
数据导入功能通过CIOManager::Import()方法实现,具有严格的文件验证机制和错误处理流程。导入过程首先验证源文件的完整性和版本兼容性,然后按顺序导入各类数据。
### 导入工作流程
```mermaid
sequenceDiagram
participant User as "用户"
participant IOManager as "CIOManager"
participant Dialog as "文件对话框"
participant DB as "目标数据库"
participant SourceDB as "源数据库"
User->>IOManager : 调用Import()
IOManager->>Dialog : 显示文件选择对话框
Dialog-->>IOManager : 返回选择的文件路径
IOManager->>SourceDB : 连接源数据库
SourceDB-->>IOManager : 连接成功
IOManager->>SourceDB : 验证数据库版本
alt 版本验证失败
SourceDB-->>IOManager : 返回错误
IOManager->>User : 显示错误消息
IOManager-->>User : 返回取消
else 版本验证成功
IOManager->>DB : 开始事务
IOManager->>DB : 导入项目数据
IOManager->>DB : 导入测区数据
IOManager->>DB : 导入脚本数据
IOManager->>DB : 导入测试数据
IOManager->>DB : 提交事务
DB-->>IOManager : 提交成功
IOManager-->>User : 返回成功
end
alt 导入过程中发生异常
IOManager->>DB : 回滚事务
IOManager-->>User : 返回失败
end
```
**图示来源**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L101-L204)
**本节来源**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L101-L204)
### 数据映射与冲突解决机制
在导入过程中,系统采用以下机制处理数据映射和潜在冲突:
1. **主键映射**:使用CHandleProcessor类处理ID映射,确保对象引用关系的正确性
2. **外键关联**:在导入测区时,根据项目CN码建立与项目的关联
3. **冲突检测**:在导入脚本时,检查是否存在相同CN码的脚本,避免重复
4. **数据完整性**:通过事务机制确保所有相关数据的一致性更新
## 文件传输协议
系统通过Zmodem协议实现串口和网络环境下的数据交换,提供了可靠的文件传输能力。
### Zmodem协议实现
```mermaid
classDiagram
class Zmodem {
+CSComPort* port
+FILE* file
+long file_length
+int file_count
+char file_name[128]
+BOOL Send(char* files[])
+BOOL Receive(CString Path)
-int SendSingleFile(char* name)
-int ReceiveSingleFile(CString Path)
-int WakeUpSender()
}
class FileTransfer {
+CSComPort* port
+FILE* file
+long file_length
+int file_count
+char file_name[128]
+virtual BOOL Send(char* files[])
+virtual BOOL Receive(CString Path)
}
class SComPort {
+HANDLE m_hCom
+DCB m_dcbBlock
+char m_aWriteBuffer[WRITEBUFFER_SIZE]
+int m_iWriteSize
+char m_aReadBuffer[READBUFFER_SIZE]
+int m_iReadSize
+BOOL OpenComm(CString szComName)
+void CloseComm()
+BOOL SendDataDirectly(char* pDataBuff, int iDataSize)
+BOOL ReceiveDataDirectly(char* pDataBuff, int* iDataSize)
+BOOL ZmodemSendDataDirectly(char* pDataBuff, int iDataSize)
+BOOL ZmodemReceiveDataDirectly(char* pDataBuff, int* iDataSize)
}
Zmodem --|> FileTransfer : "继承"
Zmodem --> SComPort : "使用"
FileTransfer --> SComPort : "使用"
```
**图示来源**
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L33-L800)
- [FileTransfer.h](file://h/FileTransfer.h#L26-L46)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L31-L800)
**本节来源**
- [Zmodem.cpp](file://cpp/Tools/Zmodem.cpp#L33-L800)
- [FileTransfer.h](file://h/FileTransfer.h#L26-L46)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L31-L800)
### 串口与网络配置
系统通过SComPort类实现串口通信,支持以下配置:
- **波特率**115200 bps
- **数据位**8位
- **停止位**1位
- **校验**:无校验
- **流控制**:无
网络通信通过相同的接口实现,确保了传输层的透明性。
## 数据完整性与事务处理
系统采用严格的事务处理机制确保数据导入导出过程中的完整性。
### 事务处理机制
```mermaid
flowchart LR
A[开始事务] --> B[导出项目数据]
B --> C[导出测区数据]
C --> D[导出测试数据]
D --> E[导出脚本数据]
E --> F{所有操作成功?}
F --> |是| G[提交事务]
F --> |否| H[回滚事务]
G --> I[关闭连接]
H --> J[删除文件]
I --> K[返回成功]
J --> L[返回失败]
```
**本节来源**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L63-L78)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L177-L188)
### 错误回滚与文件完整性验证
系统在数据处理过程中实施了多重保护机制:
1. **异常捕获**:使用try-catch块捕获COM异常
2. **自动回滚**:发生异常时自动执行RollbackTrans()
3. **文件验证**:导入前验证dbversion表确保文件兼容性
4. **资源清理**:确保数据库连接和文件句柄的正确释放
## 应用场景分析
数据导入导出模块在多种实际场景中发挥重要作用:
### 系统升级
在系统升级过程中,该模块可用于:
- 迁移旧版本数据到新系统
- 验证数据完整性
- 保持项目历史记录
### 数据迁移
支持跨设备的数据迁移:
- 从现场设备导出数据到办公室计算机
- 在不同项目团队间共享测试数据
- 备份关键项目信息
### 协作与共享
促进团队协作:
- 共享脚本配置
- 交换测试结果
- 统一数据标准
## 结论
数据导入导出模块通过CIOManager类实现了完整的数据迁移功能,采用事务处理确保数据一致性,利用Zmodem协议支持多种传输方式。该模块架构清晰,功能完善,为Geomative Studio系统的数据管理提供了可靠保障。通过严格的错误处理和完整性验证机制,确保了数据在迁移过程中的安全性和可靠性。
@@ -0,0 +1,400 @@
# 数据导出
<cite>
**本文档引用的文件**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
- [IOManager.h](file://h/IOManager.h)
- [database_modify.xml](file://database_modify.xml)
- [UpdateDataBase.cpp](file://cpp/Operator/UpdateDataBase.cpp)
</cite>
## 目录
1. [简介](#简介)
2. [数据导出架构](#数据导出架构)
3. [核心组件分析](#核心组件分析)
4. [事务处理与异常恢复](#事务处理与异常恢复)
5. [数据库模式与版本控制](#数据库模式与版本控制)
6. [结论](#结论)
## 简介
本文档全面阐述了Geomative Studio软件中数据导出功能的实现机制。该功能通过CIOManager类的Export方法,将项目、测区、测试数据等信息安全地导出到受密码保护的Access数据库(.accdb)文件中。文档详细说明了导出过程中的事务处理、树形结构遍历、数据库创建、异常处理和回滚机制,以及针对不同类型测试数据(如2D电阻率、IP)的导出实现细节。
## 数据导出架构
```mermaid
graph TD
A[用户界面] --> B[CIOManager::Export]
B --> C[创建加密数据库]
C --> D[开始事务]
D --> E[遍历树形结构]
E --> F[选择导出内容]
F --> G[导出项目数据]
F --> H[导出测区数据]
F --> I[导出测试数据]
G --> J[ExportProjectToAccdbFile]
H --> K[ExportTzToAccdbFile]
I --> L[ExportRspTdToAccdbFile]
I --> M[ExportIpspTdToAccdbFile]
L --> N[导出电阻率数据]
M --> O[导出IP数据]
N --> P[提交事务]
O --> P
P --> Q[完成导出]
B --> R[异常处理]
R --> S[回滚事务]
S --> T[删除文件]
```
**Diagram sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L35-L98)
- [IOManager.h](file://h/IOManager.h#L19)
## 核心组件分析
### CIOManager类分析
CIOManager类是数据导出功能的核心,负责协调整个导出流程。它通过ADOX和ADODB技术与Access数据库进行交互。
#### 类结构
```mermaid
classDiagram
class CIOManager {
+_ConnectionPtr m_pConnection
+ADOX : : _CatalogPtr m_pCatalog
+CHandleProcessor m_handleProcessor
+CStateProcessor m_stateProcessor
+UINT Export(void)
+UINT Import(void)
+CIOManager(_ConnectionPtr&, ADOX : : _CatalogPtr)
+~CIOManager()
}
class CHandleProcessor {
+DWORD GenerateHandle(DWORD, UINT)
+DWORD GetIDFromHandle(DWORD)
+UINT GetStyleFromHandle(DWORD)
}
class CStateProcessor {
+UINT ChangeToImageState(UINT)
+UINT ChangeToItemState(UINT)
}
CIOManager --> CHandleProcessor : "使用"
CIOManager --> CStateProcessor : "使用"
```
**Diagram sources**
- [IOManager.h](file://h/IOManager.h#L14-L48)
- [HandleProcessor.h](file://h/HandleProcessor.h#L12-L26)
- [StateProcessor.h](file://h/StateProcessor.h#L12-L20)
**Section sources**
- [IOManager.h](file://h/IOManager.h#L14-L48)
### 导出流程分析
数据导出流程从用户界面触发,通过CIOManager::Export方法启动,整个过程采用事务处理确保数据一致性。
#### 导出流程
```mermaid
sequenceDiagram
participant UI as 用户界面
participant IO as CIOManager
participant DB as Access数据库
UI->>IO : Export()
IO->>IO : 创建导出对话框
IO->>IO : 显示选择树
loop 用户选择
IO->>IO : 处理用户事件
end
IO->>IO : 用户确认导出
IO->>DB : CreateExpDatabase()
DB-->>IO : 返回连接
IO->>DB : BeginTrans()
IO->>IO : ExportDataToAccdbFile()
IO->>IO : ExportSptToAccdbFile()
IO->>DB : CommitTrans()
DB-->>IO : 提交成功
IO-->>UI : 返回成功状态
```
**Diagram sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L35-L98)
**Section sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L35-L98)
### 树形结构遍历
ExportDataToAccdbFile函数负责遍历树形结构,根据用户选择导出相应的数据。
#### 遍历逻辑
```mermaid
flowchart TD
Start([开始遍历]) --> CheckProject["检查项目节点是否选中"]
CheckProject --> |是| ExportProject["导出项目数据"]
CheckProject --> |否| NextProject["下一个项目"]
ExportProject --> CheckTz["检查测区节点是否选中"]
CheckTz --> |是| ExportTz["导出测区数据"]
CheckTz --> |否| NextTz["下一个测区"]
ExportTz --> CheckTd["检查测试数据节点是否选中"]
CheckTd --> |是| CheckType["检查测试类型"]
CheckTd --> |否| NextTd["下一个测试数据"]
CheckType --> |2D电阻率| ExportRsp["导出RspTd数据"]
CheckType --> |2D IP| ExportIpsp["导出IpspTd数据"]
ExportRsp --> NextTd
ExportIpsp --> NextTd
NextTd --> |有下一个| CheckTd
NextTd --> |无下一个| NextTz
NextTz --> |有下一个| CheckTz
NextTz --> |无下一个| NextProject
NextProject --> |有下一个| CheckProject
NextProject --> |无下一个| End([遍历完成])
```
**Diagram sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L657-L727)
**Section sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L657-L727)
## 事务处理与异常恢复
### 事务处理机制
数据导出采用严格的事务处理机制,确保数据的完整性和一致性。
#### 事务流程
```mermaid
flowchart TD
Start([开始]) --> CreateDB["创建数据库文件"]
CreateDB --> BeginTrans["开始事务"]
BeginTrans --> ExportData["导出数据"]
ExportData --> |成功| Commit["提交事务"]
ExportData --> |失败| Rollback["回滚事务"]
Commit --> CloseDB["关闭数据库"]
Commit --> ReturnSuccess["返回成功"]
Rollback --> CloseDB
Rollback --> DeleteFile["删除文件"]
Rollback --> ReturnFail["返回失败"]
CloseDB --> End([结束])
```
**Diagram sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L59-L78)
**Section sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L59-L86)
### 异常处理策略
系统实现了完善的异常处理机制,确保在导出过程中出现错误时能够正确恢复。
#### 异常处理
```mermaid
flowchart TD
Start([异常发生]) --> CatchException["捕获_com_error异常"]
CatchException --> RollbackTrans["回滚事务"]
RollbackTrans --> CloseConnection["关闭数据库连接"]
CloseConnection --> DeleteFile["删除已创建的文件"]
DeleteFile --> SetErrorCode["设置错误代码"]
SetErrorCode --> ReturnFail["返回失败状态"]
```
**Diagram sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L80-L86)
**Section sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L80-L86)
## 数据库模式与版本控制
### 数据库模式定义
CreateExpDatabase函数创建具有完整模式的Access数据库,包含多个数据表。
#### 数据库模式
```mermaid
erDiagram
project {
string CN PK
string PRname
string PRdesc
string location
date PRdate
smallint duration
string PS
string CS
string PM
string QAS
string standard
}
tz {
string TZname PK
string PRCN FK
string TZdesc
string location
}
td {
string TDname PK
string DESN
string PRCN FK
string TZname FK
string SCCN FK
smallint TDtype
string HFname
string CFname
smallint CFRamount
string GRFname
smallint GRFRamount
}
tdhead {
string TDname PK
string DESN
date Cdate
date Ctime
boolean rolling
smallint RCamount
smallint Rdirection
smallint CRtime
string CPE
string CPN
smallint weather
smallint temperature
smallint height
smallint humidity
string PM
string OP
string QA
}
parameter {
string TDname PK
string DESN
smallint LCHamount
smallint RCHamount
smallint LCamount
smallint RCamount
smallint LEamount
smallint REamount
smallint Felectrode
smallint Espacing
smallint Clayout
smallint CLfun
}
rspcon {
string TDname PK
string DESN
smallint A
smallint B
smallint M
smallint N
single K
single SP
single Ro
single Vp
single Ip
single SD
single RgA
single RgB
single RgM
single RgN
date Ttime
}
ipspcon {
string TDname PK
string DESN
single SP
single Ro
single VP
single IP
single M1
single M2
single M3
single M4
single M5
single M6
single M7
single TH
single D
single Zp
single FG
single Am
single Bm
single Cm
single Dm
single r
}
gr {
string TDname PK
string DESN
string electrode
string CableH
string CableT
single P1GR
single P2GR
}
scon {
string CN PK
string Sname
smallint Eamount
smallint CHamount
smallint TPamount
string definer
date DEdate
string SCdesc
}
channel {
string CN PK
smallint CHnumber
smallint AR
}
script {
string CN PK
smallint CHnumber
smallint TSN
smallint C1
smallint C2
smallint P1
smallint P2
single K
smallint N
}
dbversion {
string VK PK
}
project ||--o{ tz : "包含"
tz ||--o{ td : "包含"
td ||--|| tdhead : "关联"
td ||--|| parameter : "关联"
td ||--o{ rspcon : "包含"
td ||--o{ ipspcon : "包含"
td ||--o{ gr : "包含"
scon ||--o{ channel : "包含"
scon ||--o{ script : "包含"
td }|--|| scon : "使用"
```
**Diagram sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L206-L656)
**Section sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L206-L656)
### 版本控制机制
系统通过dbversion表实现数据库版本控制,确保导入导出的兼容性。
#### 版本控制流程
```mermaid
flowchart TD
Start([导入文件]) --> ReadVersion["读取dbversion表"]
ReadVersion --> |版本匹配| Continue["继续导入"]
ReadVersion --> |版本不匹配| ShowError["显示文件错误"]
Continue --> ImportData["导入数据"]
ImportData --> UpdateVersion["更新版本信息"]
UpdateVersion --> End([完成])
```
**Diagram sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L133-L158)
- [database_modify.xml](file://database_modify.xml#L2)
- [UpdateDataBase.cpp](file://cpp/Operator/UpdateDataBase.cpp#L847-L872)
**Section sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L133-L158)
- [database_modify.xml](file://database_modify.xml#L2)
- [UpdateDataBase.cpp](file://cpp/Operator/UpdateDataBase.cpp#L847-L872)
## 结论
Geomative Studio的数据导出功能通过CIOManager类实现了安全、可靠的数据导出机制。系统采用事务处理确保数据一致性,通过密码保护的Access数据库文件保证数据安全。导出过程支持树形结构选择,允许用户灵活选择要导出的内容。异常处理和回滚机制确保了在导出失败时系统能够正确恢复。数据库模式设计完整,涵盖了项目、测区、测试数据等所有必要信息,并通过版本控制机制保证了数据的兼容性。该实现为地质勘探数据的管理和共享提供了可靠的技术支持。
@@ -0,0 +1,314 @@
# 文件传输协议
<cite>
**本文档中引用的文件**
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp)
- [FileTransfer_crul.h](file://h/FileTransfer_crul.h)
- [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp)
- [LicenseUpgrade.cpp](file://cpp/Operator/LicenseUpgrade.cpp)
</cite>
## 目录
1. [项目结构](#项目结构)
2. [核心组件](#核心组件)
3. [架构概述](#架构概述)
4. [详细组件分析](#详细组件分析)
5. [依赖分析](#依赖分析)
6. [性能考虑](#性能考虑)
7. [故障排除指南](#故障排除指南)
8. [结论](#结论)
## 项目结构
该项目包含多个模块,其中文件传输功能主要位于`cpp/Tools/`目录下。关键文件包括`FileTransfer_crul.cpp``FileTransfer_crul.h`,它们实现了基于libcurl的HTTP/HTTPS文件下载功能。日志文件存储在`LOG/`目录下的`filetrans_crul_log.txt`中。
```mermaid
graph TD
A[文件传输系统] --> B[FileTransfer_crul.h]
A --> C[FileTransfer_crul.cpp]
B --> D[CFileTransfer_crul类]
C --> D
D --> E[DownloadFile方法]
D --> F[WriteToFile回调]
D --> G[GetUrlResConValild方法]
H[日志系统] --> I[LOG\\filetrans_crul_log.txt]
D --> I
```
**图示来源**
- [FileTransfer_crul.h](file://h/FileTransfer_crul.h#L55-L108)
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L24-L62)
**本节来源**
- [FileTransfer_crul.h](file://h/FileTransfer_crul.h#L1-L111)
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L1-L493)
## 核心组件
`CFileTransfer_crul`类封装了libcurl库的功能,提供了一个高层接口用于HTTP/HTTPS文件下载。该类支持连接超时设置、进度回调、错误处理等特性,并实现了安全的HTTPS传输(不验证SSL证书)。
**本节来源**
- [FileTransfer_crul.h](file://h/FileTransfer_crul.h#L55-L108)
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L24-L62)
## 架构概述
该文件传输系统采用面向对象的设计模式,通过`CFileTransfer_crul`类封装libcurl的所有功能。系统支持同步文件下载,具有完整的错误处理机制和日志记录功能。
```mermaid
classDiagram
class CFileTransfer_crul {
+m_strUrl : CString
+m_strSavePath : CString
+m_strSaveName : CString
+m_nTimeOut : int
+m_bIsNeedProgress : bool
+m_bIsHttpsFlag : bool
+m_bIsSSLCertify : bool
+DownloadFile() : bool
+SetOption() : void
+GetUrlResConValild() : bool
+WriteToFile() : size_t
+PrintLog() : void
+InitalLogInfo() : void
}
CFileTransfer_crul --> "1" "curl_easy_init" : 使用
CFileTransfer_crul --> "1" "LOG\\filetrans_crul_log.txt" : 写入日志
```
**图示来源**
- [FileTransfer_crul.h](file://h/FileTransfer_crul.h#L55-L108)
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L24-L62)
## 详细组件分析
### CFileTransfer_crul类分析
`CFileTransfer_crul`类是整个文件传输系统的核心,它封装了libcurl的所有功能,提供了简洁易用的接口。
#### 类结构分析
```mermaid
classDiagram
class CFileTransfer_crul {
<<class>>
+m_pCrEasyHandl : CURL*
+m_strUrl : CString
+m_strSavePath : CString
+m_strSaveName : CString
+m_nTimeOut : int
+m_bIsNeedProgress : bool
+m_bIsNeedErrInfo : bool
+m_bIsHttpsFlag : bool
+m_bIsSSLCertify : bool
+m_pLog : FILE*
+m_lTotalRecvFileSize : curl_off_t
+m_lCurRecvSize : curl_off_t
+m_nWriteFileSize : static int
+m_RecvFileSize : static DOUBLE
+CFileTransfer_crul()
+~CFileTransfer_crul()
+Inital() : bool
+UnInital() : void
+SetOption() : void
+DownloadFile() : bool
+GetUrlResConValild() : bool
+WriteToFile() : static size_t
+xferinfo() : static int
+PrintLog() : void
+InitalLogInfo() : void
}
```
**图示来源**
- [FileTransfer_crul.h](file://h/FileTransfer_crul.h#L55-L108)
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L24-L62)
#### 下载流程分析
`DownloadFile`方法执行完整的文件下载流程,从URL验证到文件写入:
```mermaid
sequenceDiagram
participant Client as "客户端"
participant FileTransfer as "CFileTransfer_crul"
participant Curl as "libcurl"
participant File as "目标文件"
Client->>FileTransfer : 调用DownloadFile()
FileTransfer->>FileTransfer : 验证参数
FileTransfer->>FileTransfer : 检查HTTPS设置
FileTransfer->>FileTransfer : 调用GetUrlResConValild()
FileTransfer->>Curl : curl_easy_init()
FileTransfer->>Curl : 设置各种选项
FileTransfer->>Curl : CURLOPT_URL
FileTransfer->>Curl : CURLOPT_TIMEOUT
FileTransfer->>Curl : CURLOPT_WRITEFUNCTION
FileTransfer->>Curl : CURLOPT_SSL_VERIFYPEER
FileTransfer->>File : fopen()
FileTransfer->>Curl : curl_easy_perform()
Curl->>FileTransfer : 数据块
FileTransfer->>FileTransfer : WriteToFile回调
FileTransfer->>File : fwrite()
FileTransfer->>FileTransfer : 更新进度
Curl->>FileTransfer : 下载完成
FileTransfer->>File : fclose()
FileTransfer->>Curl : curl_easy_cleanup()
FileTransfer->>Client : 返回结果
```
**图示来源**
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L150-L280)
**本节来源**
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L150-L280)
### 数据写入与完整性校验
`WriteToFile`回调函数负责将接收到的数据流式写入文件,并进行完整性校验。
```mermaid
flowchart TD
Start([开始写入]) --> ValidateInput["验证输入参数"]
ValidateInput --> WriteData["调用fwrite写入数据"]
WriteData --> CheckResult{"写入结果检查"}
CheckResult --> |成功| UpdateCounter["更新写入计数器"]
CheckResult --> |失败| LogError["记录错误日志"]
UpdateCounter --> ReturnResult["返回写入大小"]
LogError --> ReturnResult
ReturnResult --> End([结束])
```
**图示来源**
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L283-L309)
**本节来源**
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L283-L309)
### HTTPS安全策略
系统支持HTTPS但不支持SSL证书验证的安全策略,这在特定环境下提供了灵活性。
```mermaid
flowchart TD
Start([开始]) --> CheckHTTPS{"是否HTTPS?"}
CheckHTTPS --> |是| CheckCertify{"是否需要SSL验证?"}
CheckCertify --> |否| DisableVerify["设置CURLOPT_SSL_VERIFYPEER=0"]
DisableVerify --> Continue["继续下载流程"]
CheckCertify --> |是| ShowError["显示不支持SSL验证错误"]
ShowError --> End["结束"]
CheckHTTPS --> |否| Continue
Continue --> End
```
**图示来源**
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L161-L169)
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L230-L233)
**本节来源**
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L161-L169)
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L230-L233)
### 传输日志记录机制
系统实现了详细的日志记录机制,所有操作都会被记录到`LOG\filetrans_crul_log.txt`文件中。
```mermaid
classDiagram
class CFileTransfer_crul {
+m_pLog : FILE*
+InitalLogInfo() : void
+PrintLog() : void
}
CFileTransfer_crul --> "1" "LOG\\filetrans_crul_log.txt" : 写入日志
CFileTransfer_crul --> "1" "SYSTEMTIME g_sysCurTime" : 获取时间
```
日志格式包含时间戳和详细信息:
```
YYYY-MM-DD HH:MM:SS.MMM [行号] 日志内容
```
**图示来源**
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L64-L77)
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L474-L487)
**本节来源**
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L64-L77)
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L474-L487)
### 资源可用性验证
`GetUrlResConValild`函数通过HEAD请求验证资源可用性,确保下载前资源存在。
```mermaid
sequenceDiagram
participant FileTransfer as "CFileTransfer_crul"
participant Curl as "libcurl"
FileTransfer->>Curl : curl_easy_init()
FileTransfer->>Curl : 设置CURLOPT_URL
FileTransfer->>Curl : 设置CURLOPT_TIMEOUT
FileTransfer->>Curl : 设置CURLOPT_NOBODY=1
FileTransfer->>Curl : 设置CURLOPT_HEADER=1
FileTransfer->>Curl : 设置WriteFuncForUrlTest
FileTransfer->>Curl : 执行3次curl_easy_perform
loop 重试机制
Curl->>FileTransfer : 返回结果
FileTransfer->>FileTransfer : 检查是否CURLE_OK
end
FileTransfer->>Curl : curl_easy_getinfo获取响应码
FileTransfer->>FileTransfer : 检查响应码是否为200
FileTransfer->>Curl : curl_easy_cleanup()
FileTransfer->>调用者 : 返回验证结果
```
**图示来源**
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L354-L427)
**本节来源**
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L354-L427)
## 依赖分析
该文件传输系统依赖于libcurl库和Windows API,与其他模块通过清晰的接口进行交互。
```mermaid
graph TD
A[CFileTransfer_crul] --> B[libcurl]
A --> C[Windows API]
A --> D[LOG\\filetrans_crul_log.txt]
B --> E[SSL/TLS]
B --> F[HTTP/HTTPS协议]
C --> G[文件系统]
C --> H[网络接口]
I[checkupdate.cpp] --> A
J[LicenseUpgrade.cpp] --> A
```
**图示来源**
- [FileTransfer_crul.h](file://h/FileTransfer_crul.h#L7-L21)
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L21-L493)
**本节来源**
- [FileTransfer_crul.h](file://h/FileTransfer_crul.h#L7-L21)
- [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp#L735-L741)
- [LicenseUpgrade.cpp](file://cpp/Operator/LicenseUpgrade.cpp#L246-L247)
## 性能考虑
该实现采用了流式写入方式,避免了内存中缓存整个文件,从而提高了大文件下载的性能。同时,通过设置合理的超时值和重试机制,增强了网络不稳定环境下的可靠性。
## 故障排除指南
当文件下载出现问题时,可以检查以下方面:
1. 查看`LOG\filetrans_crul_log.txt`中的详细日志
2. 确认URL格式正确且资源可用
3. 检查保存路径是否有写入权限
4. 验证网络连接是否正常
5. 检查超时设置是否合理
**本节来源**
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L244-L263)
- [FileTransfer_crul.cpp](file://cpp/Tools/FileTransfer_crul.cpp#L400-L408)
## 结论
`CFileTransfer_crul`类提供了一个完整、可靠的基于libcurl的文件传输解决方案。它封装了复杂的libcurl API,提供了简洁易用的接口,同时具备完善的错误处理和日志记录功能。该实现支持HTTP/HTTPS协议,采用流式写入方式,适合大文件下载场景。通过HEAD请求预验证资源可用性,提高了下载成功率。日志系统详细记录了所有操作,便于问题排查和系统维护。
@@ -0,0 +1,130 @@
# 核心功能
<cite>
**本文档引用的文件**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
- [DevManager.h](file://h/DevManager.h)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [ProManager.h](file://h/ProManager.h)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
- [SptManager.h](file://h/SptManager.h)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp)
- [TdManager.h](file://h/TdManager.h)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
- [IOManager.h](file://h/IOManager.h)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp)
- [Project.cpp](file://cpp/ProblemZone/Project.cpp)
- [Scriptor3D.cpp](file://cpp/ProblemZone/Scriptor3D.cpp)
- [scriptor.c](file://cpp/Tools/scriptor.c)
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
</cite>
## 目录
1. [设备管理器 (DevManager)](#设备管理器-devmanager)
2. [项目管理器 (ProManager)](#项目管理器-promanager)
3. [脚本管理器 (SptManager)](#脚本管理器-sptmanager)
4. [测试数据管理器 (TdManager)](#测试数据管理器-tdmanager)
5. [IO管理器 (IOManager)](#io管理器-iomanager)
## 设备管理器 (DevManager)
设备管理器(DevManager)是系统与物理设备交互的核心组件,负责设备的连接、状态监控和固件升级。它通过`CDevice`类的实例来管理每个设备,并使用链表`m_devLinkList`在内存中维护所有设备对象。
设备管理器通过`InitialDevLinkList()`方法从数据库初始化设备列表。该方法查询`device`表,为每个设备创建`CDevice`对象,并将其添加到链表中。设备的唯一标识符是其序列号(SN),并使用`m_handleProcessor`生成唯一的句柄(Handle)进行内存管理。
当设备通过串口或网络连接到计算机时,系统会检测到新设备。设备管理器通过`GetRegisterDevice()`方法在内存链表中查找具有匹配序列号的设备。如果找到,则建立连接;如果未找到,则调用`AddOfflineObjInMem()`创建一个离线设备对象。设备的在线状态由`m_uState`属性表示,其值可以是`PZ_STATE_OFFLINE``PZ_STATE_ONLINE``PZ_STATE_NEW`
对于固件升级,设备管理器本身不直接执行升级操作,而是作为协调者。当用户请求升级时,系统会通过`CDevice`对象与设备通信,发送升级命令和固件文件。设备管理器通过`UpdateDevInfo()`方法接收来自设备的更新信息(如硬件版本HWV、软件版本SWV、电池电压等),并将其同步到数据库中,确保本地信息与设备状态一致。
**Section sources**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L1-L661)
- [DevManager.h](file://h/DevManager.h#L1-L69)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L90-L2662)
## 项目管理器 (ProManager)
项目管理器(ProManager)负责管理项目的整个生命周期,包括创建、配置测区和与设备同步。它使用`CLinkList<CDataMngStruct*>`链表`m_dmsLinkList`来管理项目(Project)和测区(TestingZone)对象。
项目管理器通过`CreateProjectInDB()`方法在数据库中创建新项目。该方法首先显示一个对话框(`COpCreateProjectDlg`)供用户输入项目信息(如项目名称、描述、位置等)。为确保项目名称的唯一性,它会查询数据库进行检查。创建成功后,系统会自动调用`InsertDefaultTzToProject()`为该项目创建一个默认测区。
项目与设备的同步是通过文件传输实现的。`CreateProjectInDev()`方法负责将项目从数据库同步到设备。它首先查询数据库获取项目信息,然后使用`CMarkup`类生成一个名为`project.xml`的XML配置文件。此文件被写入本地缓存目录(`CACHE\projects\<ProjectCN>\`),最后通过`CDevice::SendFile()`方法将文件传输到设备的SD卡指定路径(`/SD/projects/<ProjectCN>/`)。
测区的管理与项目类似。`CreateTzInDev()`方法创建测区配置文件`testzone.xml`,并将其同步到设备。该文件包含了测区的类型、位置、描述等元数据。当用户在设备上完成测量后,可以通过`LoadProjectFromDev()``LoadTzFromDev()`方法将数据从设备上载回计算机,实现数据的双向同步。
**Section sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L1-L800)
- [ProManager.h](file://h/ProManager.h#L1-L77)
- [Project.cpp](file://cpp/ProblemZone/Project.cpp#L1-L36)
## 脚本管理器 (SptManager)
脚本管理器(SptManager)负责生成2D/3D测量脚本。它通过`CLinkList<CScript*>`链表`m_sptLinkList`管理脚本对象,并利用`m_medLinkList`管理各种测量装置(Medium)。
脚本的创建过程始于用户选择测量类型(如温纳、施伦贝谢等)。`Create2DSConInDB()`方法处理2D脚本的创建。它首先显示一个对话框(`COpCreateSptDlg`)供用户配置参数。脚本的核心是测点(Test Point)的生成,这由底层的`scriptor`库完成。`scriptor.c`文件中的`scr_generate()`函数根据用户定义的装置类型和区域边界,计算出所有电极的排列组合(A, B, M, N)和对应的几何因子(K)。
对于3D脚本,系统使用`Scriptor3D`类。该类封装了`scriptor`库的3D功能,通过`SetRect()`定义测量区域,并通过`generate()`方法生成脚本。生成的脚本数据被持久化到数据库的`scon``channel``script2d`表中。
脚本管理器还负责脚本的导出和导入。`PutScriptToDev()`方法将数据库中的脚本转换为设备可识别的格式(如`.scr`文件),并通过`CDevice::SendFile()`传输到设备。`LoadScriptFromDev()`则执行相反的操作,将设备上的脚本文件解析并导入到数据库中。
```mermaid
flowchart TD
A[用户选择测量类型] --> B[显示配置对话框]
B --> C[调用底层scriptor库]
C --> D[生成测点序列]
D --> E[保存到数据库]
E --> F[生成.scr文件]
F --> G[传输到设备]
```
**Diagram sources **
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L1-L800)
- [SptManager.h](file://h/SptManager.h#L1-L88)
- [Scriptor3D.cpp](file://cpp/ProblemZone/Scriptor3D.cpp#L1-L69)
- [scriptor.c](file://cpp/Tools/scriptor.c#L1-L70)
**Section sources**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L1-L800)
- [SptManager.h](file://h/SptManager.h#L1-L88)
## 测试数据管理器 (TdManager)
测试数据管理器(TdManager)负责处理测量数据的采集和存储。它使用`CLinkList<CTestingData*>`链表`m_tdLinkList`来管理所有测试数据对象。
数据采集流程始于用户在设备上启动测量任务。任务完成后,用户通过`Upload2DTdFromDev()`等方法将数据从设备上载到计算机。此过程首先调用`ImportTdHeadToDB()`将任务的元数据(如任务名称、设备序列号、测量参数等)从`*.xml`文件导入数据库的`td`表,创建一个新的测试数据记录。
随后,`Import2DTdOrgToDB()``Import2DTdConToDB()`方法分别处理原始数据(`*.org`文件)和计算结果数据(`*.dat`文件)的导入。原始数据包含未经处理的电压、电流读数,而计算结果数据包含已计算出的电阻率(Ro)、视极化率(SP)等。这些数据被解析并存入`rspcon``ipspcon`等专用数据表中。
数据的展示通过`ShowTdListByTz()`等方法实现。这些方法查询数据库,将数据填充到列表控件(`CListCtrl`)中,供用户查看。此外,`Convert2DTo3D()`方法提供了一个高级功能,允许用户将多个2D剖面数据合并转换为3D数据集,以便进行三维可视化分析。
**Section sources**
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L1-L800)
- [TdManager.h](file://h/TdManager.h#L1-L109)
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L228-L290)
## IO管理器 (IOManager)
IO管理器(IOManager)实现了数据的导入和导出功能,主要用于与其他系统或用户进行数据交换。其核心功能是`Export()``Import()`方法。
`Export()`方法允许用户将项目、测区、脚本和测试数据导出为一个独立的`.accdb`(Access数据库)文件。该过程首先通过`CreateExpDatabase()`创建一个新的空数据库,并使用`ADOX`库定义其表结构(如`project``tz``td`等)。然后,`ExportDataToAccdbFile()`遍历一个树形控件(`CTreeCtrl`),根据用户的选择,将数据从主数据库复制到新创建的`.accdb`文件中。
`Import()`方法执行相反的操作。它首先验证用户选择的`.accdb`文件是否为有效的导出文件(通过检查`dbversion`表)。验证通过后,`ImportProjectToDB()``ImportTzToDB()`等方法会将文件中的数据逐项导入到主数据库中。这个过程确保了数据的完整性和一致性,支持跨设备或跨版本的数据迁移。
```mermaid
flowchart LR
A[用户选择导出] --> B[创建空.accdb文件]
B --> C[定义表结构]
C --> D[从主数据库复制数据]
D --> E[生成最终文件]
E --> F[用户选择导入]
F --> G[验证文件]
G --> H[将数据导入主数据库]
```
**Diagram sources **
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L800-L1200)
- [IOManager.h](file://h/IOManager.h#L1-L52)
**Section sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1-L2064)
- [IOManager.h](file://h/IOManager.h#L1-L52)
@@ -0,0 +1,166 @@
# 数据导出
<cite>
**本文档引用的文件**
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp)
- [IOManager.cpp](file://cpp/Managers/IOManager.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)
- [Rsp2DTd.cpp](file://cpp/ProblemZone/Rsp2DTd.cpp)
- [RspCETd.cpp](file://cpp/ProblemZone/RspCETd.cpp)
- [SP2DTd.cpp](file://cpp/ProblemZone/SP2DTd.cpp)
- [TdManager.h](file://h/TdManager.h)
- [IOManager.h](file://h/IOManager.h)
- [excel.h](file://h/excel.h)
- [OperTxtFile.h](file://h/OperTxtFile.h)
- [OperUrfFile.h](file://h/OperUrfFile.h)
- [ioexpdlg.cpp](file://cpp/Views/ioexpdlg.cpp)
- [ioexpdmsdlg.cpp](file://cpp/Views/ioexpdmsdlg.cpp)
- [ioexpsptdlg.cpp](file://cpp/Views/ioexpsptdlg.cpp)
- [ioexpdlg.h](file://h/ioexpdlg.h)
- [ioexpdmsdlg.h](file://h/ioexpdmsdlg.h)
- [ioexpsptdlg.h](file://h/ioexpsptdlg.h)
</cite>
## 目录
1. [引言](#引言)
2. [核心组件分析](#核心组件分析)
3. [数据导出格式与数据结构映射](#数据导出格式与数据结构映射)
4. [Excel导出功能实现](#excel导出功能实现)
5. [用户自定义导出选项处理](#用户自定义导出选项处理)
6. [导出过程中的进度反馈与错误处理](#导出过程中的进度反馈与错误处理)
7. [大文件生成的内存优化方案](#大文件生成的内存优化方案)
## 引言
本文档旨在全面文档化Geomative Studio软件中测试数据导出功能的实现。该功能主要由`CTdManager``CIOManager`两个核心管理类协同工作,支持将测试数据导出为Excel、CSV、TXT、URF等多种格式。文档将详细阐述其技术细节,包括不同格式的数据结构映射规则、用户自定义选项的处理逻辑、Excel导出中`excel.cpp`类库的使用流程,以及导出过程中的进度反馈、错误处理和内存优化策略。
## 核心组件分析
`CTdManager``CIOManager`是实现数据导出功能的两个核心类。
`CTdManager`类(位于`cpp/Managers/TdManager.cpp`)是测试数据的管理核心。它负责从数据库中获取测试数据,并提供将数据保存为特定文件格式的接口。例如,`CRsp2DTd``CRspCETd`等具体的数据类型类继承自`CTestingData`,并实现了`SaveTdToExcelFile``SaveTdToCsvFile`等方法,这些方法定义了如何将特定类型的数据组织并写入文件。
`CIOManager`类(位于`cpp/Managers/IOManager.cpp`)则负责更高层次的导出流程控制。其`Export`方法启动导出流程,创建一个导出对话框(`CIOExpDlg`),用户可以在其中选择要导出的项目、测区和具体的测试数据。`CIOManager`根据用户的选择,调用`CTdManager`提供的接口来执行实际的数据导出操作。
**Section sources**
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
- [TdManager.h](file://h/TdManager.h)
- [IOManager.h](file://h/IOManager.h)
## 数据导出格式与数据结构映射
系统支持将测试数据导出为四种主要格式:Excel、CSV、TXT和URF。每种格式都有其特定的数据结构映射规则。
对于**Excel和CSV**格式,数据通常被组织成多个工作表或数据块。以`CRsp2DTd`类为例,其`SaveTdToExcelFile`方法会创建一个Excel工作簿,并包含三个工作表:
1. **Head (头部信息)**: 包含测试任务的元数据,如任务名称、位置、日期、设备信息等。
2. **DAT (数据信息)**: 包含核心的测量数据,如电极配置(A, B, M, N)、视电阻率(Ro)、电压(V)、电流(I)等。
3. **GR (接地电阻)**: 包含各电极的接地电阻测量值。
**TXT**格式的导出由`COperTxtFile`类(位于`cpp/Tools/OperTxtFile.cpp`)处理。该类提供了一个可配置的文本文件写入器,通过`SetParamWidth`方法设置每列的宽度,并使用`WriteFileContent`方法将字符串数组按固定宽度写入文件,确保数据在文本编辑器中对齐。
**URF**Universal Resistivity data File)是一种专用于电阻率数据的通用格式。其导出由`COperUrfFile`类(位于`cpp/Tools/OperUrfFile.cpp`)负责。URF文件的结构包括一个头部注释,然后是电极坐标信息,最后是测量数据。`COperUrfFile`类提供了针对不同电极阵列(如温纳装置、施伦贝谢装置、跨孔装置等)生成电极坐标的专用方法,如`WriteElecByWenSch``WriteElecByCrossHoleGeomative`,确保导出的URF文件符合特定的地质勘探软件要求。
**Section sources**
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp)
- [Rsp2DTd.cpp](file://cpp/ProblemZone/Rsp2DTd.cpp)
- [RspCETd.cpp](file://cpp/ProblemZone/RspCETd.cpp)
- [OperTxtFile.h](file://h/OperTxtFile.h)
- [OperUrfFile.h](file://h/OperUrfFile.h)
## Excel导出功能实现
Excel导出功能的核心是`excel.cpp``excel.h`文件。这两个文件是通过Visual C++的ClassWizard工具从Microsoft Excel的类型库生成的C++包装类,它们提供了对Excel应用程序对象模型的COM接口访问。
导出过程遵循以下操作流程:
1. **创建Excel应用实例**:
```cpp
_Application* pComApp = new _Application;
```
这行代码创建了一个Excel应用程序的COM对象实例。
2. **创建和获取工作簿与工作表**:
```cpp
Workbooks comBooks;
_Workbook comBook;
Sheets comSheets;
_Worksheet comSheet01;
```
通过`_Application`对象,可以获取`Workbooks`集合,进而创建一个新的工作簿(`comBook`),并从工作簿中获取`Sheets`集合来操作具体的工作表。
3. **创建工作表并命名**:
```cpp
comSheet01 = comSheets.GetItem(COleVariant((short)1));
comSheet01.SetName(_T("Head"));
```
使用`GetItem`方法获取第一个工作表,并使用`SetName`方法将其重命名为"Head"。
4. **写入数据**:
具体的数据写入逻辑由`CTestingData`的派生类(如`CRsp2DTd`)实现。这些类会调用`SaveTdHeadToExcelFile`等方法,通过遍历数据库记录集(`_RecordsetPtr`),并将数据逐行写入到`_Worksheet`对象的单元格中。
5. **应用样式和公式**:
虽然在提供的代码片段中未直接体现,但`_Worksheet`和`Range`对象提供了丰富的属性和方法来设置单元格格式(如字体、颜色、边框)和应用公式。例如,可以通过`GetRange`方法获取一个单元格区域,然后设置其`NumberFormat`属性来定义数字显示格式。
6. **保存并清理**:
```cpp
comBook.SaveAs(COleVariant(f_szFileName), covOptional, ...);
...
pComApp->Quit();
delete pComApp;
```
使用`SaveAs`方法将工作簿保存到指定路径。最后,必须显式调用`Quit`方法退出Excel应用,并释放所有COM对象指针,以避免内存泄漏。
**Section sources**
- [excel.cpp](file://cpp/Tools/excel.cpp)
- [excel.h](file://h/excel.h)
- [Rsp2DTd.cpp](file://cpp/ProblemZone/Rsp2DTd.cpp)
- [RspCETd.cpp](file://cpp/ProblemZone/RspCETd.cpp)
## 用户自定义导出选项处理
用户自定义导出选项主要通过导出对话框(`CIOExpDlg`)来处理。该对话框由`CIOManager`在`Export`方法中创建。
1. **字段选择**:
对话框中的树形控件(`CTreeCtrl`)允许用户通过复选框选择要导出的具体项目、测区和测试数据。`CIOManager`通过遍历树形控件,检查每个节点的选中状态,来确定最终需要导出的数据集。
2. **时间范围和单位系统**:
在提供的代码中,时间范围和单位系统的处理逻辑并未直接体现。这些选项很可能在`CTestingData`类的`SaveTdTo...File`方法内部实现。当从数据库查询数据时,会根据用户在UI中选择的时间范围构建SQL查询语句的`WHERE`子句。单位系统(如米/英尺)的转换则可能在数据写入文件之前,在内存中对数值进行换算。
**Section sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
- [ioexpdlg.cpp](file://cpp/Views/ioexpdlg.cpp)
- [ioexpdlg.h](file://h/ioexpdlg.h)
## 导出过程中的进度反馈与错误处理
### 进度反馈
在提供的代码中,导出过程是同步执行的,没有明确的进度条或百分比反馈机制。整个过程在用户点击“确定”后,直到完成或出错才会返回控制权。更完善的实现可能需要在`CIOManager`或`CTdManager`中引入后台线程,并通过Windows消息或回调函数向UI发送进度更新。
### 错误处理
系统采用了多层次的错误处理策略:
1. **文件操作错误**: 在打开或写入文件时,会检查返回值(如`fopen`是否返回`NULL`)。如果失败,会通过`AfxMessageBox`或`MessageBoxEx`向用户显示错误信息,包括错误代码(`GetLastError()`)。
2. **数据库操作错误**: 使用`try-catch`块捕获`_com_error`异常,当执行数据库查询或操作失败时,会弹出错误对话框。
3. **逻辑错误**: 在执行关键操作前进行参数验证。例如,`COperTxtFile::SetParamWidth`会检查输入的宽度是否在有效范围内(6-50),否则会提示错误。
4. **COM接口错误**: 在使用`excel.cpp`进行Excel操作时,虽然代码中没有显式捕获异常,但应假设`_Application`等对象的方法调用可能失败,需要进行返回值检查。
**Section sources**
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp)
- [Rsp2DTd.cpp](file://cpp/ProblemZone/Rsp2DTd.cpp)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
## 大文件生成的内存优化方案
对于大文件的生成,系统主要通过以下方式优化内存使用:
1. **流式写入 (Streaming)**: 所有文件导出操作都采用流式写入。无论是TXT、CSV还是URF文件,代码都是在打开文件后,一边从数据库读取记录,一边立即写入文件流(`fwrite`),然后立即处理下一条记录。这种方式避免了将整个数据集加载到内存中,从而将内存占用保持在较低水平。
2. **分块处理**: 数据库查询使用`_RecordsetPtr`,它本质上是一个游标,允许逐行遍历结果集,而不是一次性将所有数据加载到内存。
3. **及时释放资源**: 在操作完成后,代码会显式关闭文件句柄(`fclose`)、关闭数据库记录集(`Close()`)并释放COM对象(`ReleaseDispatch()`),确保资源被及时回收。
**Section sources**
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp)
- [Rsp2DTd.cpp](file://cpp/ProblemZone/Rsp2DTd.cpp)
@@ -0,0 +1,230 @@
# 数据展示与分析
<cite>
**本文档引用的文件**
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp)
- [appdatatdgrlistview.cpp](file://cpp/Views/appdatatdgrlistview.cpp)
- [appdatatdlistview.h](file://h/appdatatdlistview.h)
- [appdatatdgrlistview.h](file://h/appdatatdgrlistview.h)
- [appdataipsp2dtdview.cpp](file://cpp/Views/appdataipsp2dtdview.cpp)
- [appdatarsp2dtdview.cpp](file://cpp/Views/appdatarsp2dtdview.cpp)
- [appdatarspcetdview.cpp](file://cpp/Views/appdatarspcetdview.cpp)
- [DataMngStruct.h](file://h/DataMngStruct.h)
</cite>
## 目录
1. [项目结构](#项目结构)
2. [核心组件](#核心组件)
3. [架构概述](#架构概述)
4. [详细组件分析](#详细组件分析)
5. [依赖分析](#依赖分析)
## 项目结构
Geomative Studio项目是一个地质勘探数据处理软件,其核心功能包括测试数据的展示与分析。项目结构清晰地分为多个模块,其中与数据展示直接相关的文件主要位于`cpp/Views``h`目录下。关键的测试数据展示组件包括列表视图(appdatatdlistview)和图形化视图(appdatatdgrlistview),这些组件负责渲染测试数据、处理用户交互以及实现数据可视化。
```mermaid
graph TB
subgraph "视图层"
A[appdatatdlistview] --> |继承| B[CListView]
C[appdatatdgrlistview] --> |继承| B
D[appdataipsp2dtdview] --> |继承| E[CView]
F[appdatarsp2dtdview] --> |继承| E
G[appdatarspcetdview] --> |继承| E
end
subgraph "数据管理"
H[DataMngStruct]
end
A --> H
C --> H
D --> A
D --> C
F --> A
F --> C
G --> A
C --> G
```
**图表来源**
- [appdatatdlistview.h](file://h/appdatatdlistview.h#L16)
- [appdatatdgrlistview.h](file://h/appdatatdgrlistview.h#L16)
- [appdataipsp2dtdview.cpp](file://cpp/Views/appdataipsp2dtdview.cpp#L23)
- [appdatarsp2dtdview.cpp](file://cpp/Views/appdatarsp2dtdview.cpp#L22)
- [appdatarspcetdview.cpp](file://cpp/Views/appdatarspcetdview.cpp#L24)
- [DataMngStruct.h](file://h/DataMngStruct.h#L14)
**章节来源**
- [appdatatdlistview.h](file://h/appdatatdlistview.h#L1-L68)
- [appdatatdgrlistview.h](file://h/appdatatdgrlistview.h#L1-L63)
## 核心组件
测试数据展示功能的核心组件包括`CAppDataTdListView``CAppDataTdGrListView`,分别负责以列表和图形化方式展示测试数据。`CAppDataTdListView`提供了数据的表格化展示,支持列排序、批量导出和删除等操作。`CAppDataTdGrListView`则通过自定义绘制实现了数据的颜色编码,能够根据测量状态(如短路、开路、大电阻等)以不同颜色显示数据项,便于用户快速识别异常情况。
**章节来源**
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp#L24-L485)
- [appdatatdgrlistview.cpp](file://cpp/Views/appdatatdgrlistview.cpp#L23-L189)
## 架构概述
系统的数据展示架构采用MVC模式,视图层由多个继承自MFC框架的视图类组成。`CAppDataTdListView``CAppDataTdGrListView`作为具体的视图实现,通过消息映射机制响应用户交互事件。不同测量模式(如2D、3D、CE)的数据展示通过专门的视图类(如`CAppDataIpsp2DTdView``CAppDataRsp2DTdView``CAppDataRspCETdView`)来实现,这些视图类通过分割窗口将详细信息、内容列表和图形化视图组织在一起,形成统一的用户界面。
```mermaid
classDiagram
class CAppDataTdListView {
+OnInitialUpdate()
+OnColumnclick()
+OnDblclk()
+OnBatchexport()
+OnBatchDelData()
}
class CAppDataTdGrListView {
+OnInitialUpdate()
+OnColumnclick()
+OnCustomDrawList()
}
class CAppDataIpsp2DTdView {
+Create()
+OnSize()
}
class CAppDataRsp2DTdView {
+Create()
+OnSize()
}
class CAppDataRspCETdView {
+Create()
+OnSize()
}
CAppDataTdListView <|-- CAppDataIpsp2DTdView
CAppDataTdListView <|-- CAppDataRsp2DTdView
CAppDataTdListView <|-- CAppDataRspCETdView
CAppDataTdGrListView <|-- CAppDataIpsp2DTdView
CAppDataTdGrListView <|-- CAppDataRsp2DTdView
CAppDataTdGrListView <|-- CAppDataRspCETdView
```
**图表来源**
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp#L24-L485)
- [appdatatdgrlistview.cpp](file://cpp/Views/appdatatdgrlistview.cpp#L23-L189)
- [appdataipsp2dtdview.cpp](file://cpp/Views/appdataipsp2dtdview.cpp#L23-L117)
- [appdatarsp2dtdview.cpp](file://cpp/Views/appdatarsp2dtdview.cpp#L22-L118)
- [appdatarspcetdview.cpp](file://cpp/Views/appdatarspcetdview.cpp#L24-L134)
## 详细组件分析
### 列表视图分析
`CAppDataTdListView`组件实现了测试数据的列表化展示,通过`OnInitialUpdate`方法初始化列标题,支持用户通过点击列标题进行排序。该组件还实现了批量导出和删除功能,通过进度条和状态提示为用户提供操作反馈。
```mermaid
flowchart TD
Start([初始化视图]) --> InsertColumns["插入列标题"]
InsertColumns --> SetExtendedStyle["设置扩展样式"]
SetExtendedStyle --> EnableSorting["启用列排序"]
EnableSorting --> EnableSelection["启用选择功能"]
EnableSelection --> End([视图准备就绪])
```
**图表来源**
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp#L80-L271)
**章节来源**
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp#L1-L485)
### 图形化视图分析
`CAppDataTdGrListView`组件通过`OnCustomDrawList`方法实现了数据项的自定义绘制,根据测量状态应用不同的文本颜色。短路和开路状态显示为红色,大电阻状态显示为蓝色,正常状态显示为黑色,这种颜色编码策略有助于用户快速识别异常测量值。
```mermaid
flowchart TD
Start([自定义绘制]) --> CheckStage["检查绘制阶段"]
CheckStage --> PrePaint{"预绘制阶段?"}
PrePaint --> |是| NotifyItemDraw["通知项目绘制"]
PrePaint --> |否| ItemPrePaint{"项目预绘制?"}
ItemPrePaint --> |是| NotifySubItemDraw["通知子项目绘制"]
ItemPrePaint --> |否| SubItemDraw{"子项目绘制?"}
SubItemDraw --> |是| GetStatus["获取状态文本"]
GetStatus --> CheckStatus{"状态为短路/开路?"}
CheckStatus --> |是| SetRed["设置红色文本"]
CheckStatus --> |否| CheckLargeRes{"状态为大电阻?"}
CheckLargeRes --> |是| SetBlue["设置蓝色文本"]
CheckLargeRes --> |否| SetBlack["设置黑色文本"]
SetRed --> End
SetBlue --> End
SetBlack --> End
```
**图表来源**
- [appdatatdgrlistview.cpp](file://cpp/Views/appdatatdgrlistview.cpp#L145-L188)
**章节来源**
- [appdatatdgrlistview.cpp](file://cpp/Views/appdatatdgrlistview.cpp#L1-L189)
### 测量模式视图分析
不同测量模式的视图类(如`CAppDataIpsp2DTdView``CAppDataRsp2DTdView``CAppDataRspCETdView`)通过创建分割窗口来组织界面布局。每个视图包含三个主要部分:详细信息面板、内容列表和图形化视图,这种一致的布局设计为用户提供了统一的操作体验。
```mermaid
sequenceDiagram
participant View as CAppDataIpsp2DTdView
participant Splitter1 as m_firstSplitter
participant Splitter2 as m_secondSplitter
participant Detail as CAppDataTdDetailListView
participant Content as CAppDataIpsp2DTdConListView
participant Graph as CAppDataTdGrListView
View->>View : Create()
View->>Splitter1 : CreateStatic(1,2)
Splitter1->>Splitter1 : CreateView(详细信息)
Splitter1->>Splitter2 : CreateStatic(2,1)
Splitter2->>Splitter2 : CreateView(内容列表)
Splitter2->>Splitter2 : CreateView(图形化视图)
Splitter2->>Splitter2 : RecalcLayout()
Splitter1->>Splitter1 : RecalcLayout()
```
**图表来源**
- [appdataipsp2dtdview.cpp](file://cpp/Views/appdataipsp2dtdview.cpp#L69-L102)
- [appdatarsp2dtdview.cpp](file://cpp/Views/appdatarsp2dtdview.cpp#L68-L103)
- [appdatarspcetdview.cpp](file://cpp/Views/appdatarspcetdview.cpp#L67-L117)
**章节来源**
- [appdataipsp2dtdview.cpp](file://cpp/Views/appdataipsp2dtdview.cpp#L1-L117)
- [appdatarsp2dtdview.cpp](file://cpp/Views/appdatarsp2dtdview.cpp#L1-L118)
- [appdatarspcetdview.cpp](file://cpp/Views/appdatarspcetdview.cpp#L1-L134)
## 依赖分析
测试数据展示组件依赖于MFC框架的`CListView``CView`基类,通过继承和重写虚函数来实现特定功能。这些组件还依赖于`DataMngStruct`类来获取和管理测试数据,形成了清晰的依赖关系。不同测量模式的视图类共享相同的列表和图形化视图组件,体现了代码的复用性。
```mermaid
graph TD
A[CAppDataTdListView] --> B[CListView]
C[CAppDataTdGrListView] --> B
D[CAppDataIpsp2DTdView] --> E[CView]
F[CAppDataRsp2DTdView] --> E
G[CAppDataRspCETdView] --> E
A --> H[DataMngStruct]
C --> H
D --> A
D --> C
F --> A
F --> C
G --> A
G --> C
```
**图表来源**
- [appdatatdlistview.h](file://h/appdatatdlistview.h#L16)
- [appdatatdgrlistview.h](file://h/appdatatdgrlistview.h#L16)
- [appdataipsp2dtdview.cpp](file://cpp/Views/appdataipsp2dtdview.cpp#L23)
- [appdatarsp2dtdview.cpp](file://cpp/Views/appdatarsp2dtdview.cpp#L22)
- [appdatarspcetdview.cpp](file://cpp/Views/appdatarspcetdview.cpp#L24)
- [DataMngStruct.h](file://h/DataMngStruct.h#L14)
**章节来源**
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp#L1-L485)
- [appdatatdgrlistview.cpp](file://cpp/Views/appdatatdgrlistview.cpp#L1-L189)
- [appdataipsp2dtdview.cpp](file://cpp/Views/appdataipsp2dtdview.cpp#L1-L117)
- [appdatarsp2dtdview.cpp](file://cpp/Views/appdatarsp2dtdview.cpp#L1-L118)
- [appdatarspcetdview.cpp](file://cpp/Views/appdatarspcetdview.cpp#L1-L134)
- [DataMngStruct.h](file://h/DataMngStruct.h#L1-L23)
@@ -0,0 +1,271 @@
# 数据采集与存储
<cite>
**本文档引用的文件**
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp)
- [TdManager.h](file://h/TdManager.h)
- [TestingData.h](file://h/TestingData.h)
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
- [DevManager.h](file://h/DevManager.h)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp)
- [TdRecord.cpp](file://cpp/ProblemZone/TdRecord.cpp)
</cite>
## 目录
1. [引言](#引言)
2. [数据采集机制](#数据采集机制)
3. [数据存储结构](#数据存储结构)
4. [时间戳同步与采样控制](#时间戳同步与采样控制)
5. [异常数据过滤与完整性校验](#异常数据过滤与完整性校验)
6. [缓存机制与内存管理](#缓存机制与内存管理)
7. [断点续传与数据库交互](#断点续传与数据库交互)
8. [结论](#结论)
## 引言
本文档深入分析Geomative Studio软件中测试数据采集与存储机制的实现细节。系统通过CTdManager类协调设备管理器,实现对地质勘探设备的实时数据采集,包括电阻率、电流、电压、自电位等关键物理量。文档详细阐述了数据存储结构的设计原理、时间同步机制、异常数据处理策略以及与数据库的交互方式,为系统维护和功能扩展提供技术参考。
## 数据采集机制
CTdManager类作为数据采集的核心控制器,通过设备管理器获取实时测量数据。该类继承自CObject,负责管理测试数据的生命周期和采集流程。系统通过CTdManager的Upload2DTdFromDev等方法从设备上载2D数据,这些方法接收工程编号、测区编号、测试数据编号和设备指针作为参数,实现数据的远程采集。
数据采集过程中,CTdManager通过CDevice类与物理设备进行通信。CDevice类封装了设备的所有属性和操作方法,包括设备序列号(m_szDevSN)、设备名称(m_szDevName)、硬件版本(m_szHWV)和软件版本(m_szSWV)等。设备状态通过m_uState成员变量维护,支持离线(PZ_STATE_OFFLINE)、在线(PZ_STATE_ONLINE)等多种状态。
采集的数据类型由EN_DATA_TYPE枚举定义,包括电阻率测试(EN_RES_TEST_TYPE)、激电测试(EN_IP_TEST_TYPE)和自电位测试(EN_SP_TEST_TYPE)三种。系统通过不同的数据通道(tdchannel)管理不同类型的数据采集任务,确保数据的分类存储和高效处理。
**Section sources**
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L57-L6839)
- [TdManager.h](file://h/TdManager.h#L16-L21)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L43-L83)
## 数据存储结构
### TestingData类设计
TestingData类是数据存储的核心数据结构,采用面向对象的设计模式,封装了测试数据的所有属性和操作方法。该类通过成员变量定义了丰富的数据字段,涵盖了测试任务的各个方面。
**核心字段定义:**
- **标识信息**m_dwID(数据ID)、m_szTdName(测试名称)、m_szTLocation(测试位置)
- **配置参数**m_iSType(装置类型)、m_iTType(测试类型)、m_iTMode(测试模式)
- **电极参数**m_iEAmount(电极数量)、m_fESpace(电极步长)、m_szEDistance(电极间距)
- **环境参数**m_iWeather(天气)、m_fTemperature(温度)、m_fHumidity(湿度)
- **时间信息**m_szCDate(创建日期)、m_szCTime(创建时间)、m_szTDate(测试日期)、m_szTTime(测试时间)
```mermaid
classDiagram
class CTestingData {
+DWORD m_dwID
+CString m_szTdName
+CString m_szTLocation
+int m_iSType
+int m_iTType
+int m_iEAmount
+float m_fESpace
+CString m_szEDistance
+int m_iWeather
+float m_fTemperature
+float m_fHumidity
+CString m_szCDate
+CString m_szCTime
+_WaveCount *m_waveCount
+bool CalculateTWInfo(CStringArray*, int)
+bool CalculateTimeWindows(struct _WinTimeList, CStringArray*, int, int, int, int, int)
+double adc_calculate(double, double, double)
+double adc_average(int*, int)
+double adc_integral(int*, int)
}
class _WaveCount {
+int WaveLength
+_WinTimeList windowList[2]
}
class _WinTimeList {
+int ListLength
+double wintime_Vp
+_WinTime timeWinList[10]
}
class _WinTime {
+int wintime_StartTime
+int wintime_width
+double wintime_V2
+double wintime_Integral
+double wintime_ETA
+double wintime_M
}
CTestingData --> _WaveCount : "包含"
_WaveCount --> _WinTimeList : "包含"
_WinTimeList --> _WinTime : "包含"
```
**Diagram sources**
- [TestingData.h](file://h/TestingData.h#L12-L31)
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L251-L273)
### 数据库表结构
系统采用关系型数据库存储测试数据,主要表结构包括:
- **td表**:存储测试任务基本信息,包含ID、TDname、Tlocation、DESN、SCCN等字段
- **tdchannel表**:存储数据通道信息,与td表通过TDID关联
- **td2dcon表**:存储2D测试数据,包含TSN、C1、C2、P1、P2、K、I、V、R0、SP等测量值
- **td1dcon表**:存储1D测试数据,结构与td2dcon类似
- **gr表**:存储接地电阻数据,包含TDID、Ecode、Mdate、Mtime、OMvalue等字段
数据存储采用分页机制,通过ONE_PAGE_DATA_NUMBER常量定义每页数据量为100条,提高大数据量下的查询效率。
**Section sources**
- [TestingData.h](file://h/TestingData.h#L176-L224)
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L29-L77)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L121-L144)
## 时间戳同步与采样控制
### 时间戳同步机制
系统通过m_szCDate和m_szCTime字段记录数据创建的时间戳,确保数据的时间一致性。时间戳采用"YYYY-MM-DD"和"HH:MM:SS"格式存储,便于数据库查询和数据分析。在数据采集过程中,系统通过Tm2LocalStr等函数将时间戳转换为本地时间格式,保证跨时区操作的一致性。
```mermaid
sequenceDiagram
participant 设备 as 地质勘探设备
participant CTdManager as CTdManager
participant 数据库 as 数据库
设备->>CTdManager : 发送测量数据包
CTdManager->>CTdManager : 解析数据包,提取时间戳
CTdManager->>CTdManager : 调用Tm2LocalStr转换为本地时间
CTdManager->>数据库 : 插入数据记录,包含时间戳
数据库-->>CTdManager : 返回插入结果
CTdManager-->>设备 : 确认数据接收
```
**Diagram sources**
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L50-L51)
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L214-L217)
### 采样频率控制
采样频率由m_iIFrequency和m_iSAFrequency字段控制,分别表示工业频率和采样频率。系统通过GetSample方法根据工业频率和采样类型计算实际采样率:
```mermaid
flowchart TD
Start([开始]) --> CheckIndustrialFreq["检查工业频率"]
CheckIndustrialFreq --> |50Hz| SetSampleRate50["设置采样率: 30/60/120"]
CheckIndustrialFreq --> |60Hz| SetSampleRate60["设置采样率: 36/72/144"]
SetSampleRate50 --> ApplySampling["应用采样率"]
SetSampleRate60 --> ApplySampling
ApplySampling --> End([结束])
```
采样控制算法通过波形类型(m_iTRWave)和周期(f_Tcycle)计算每段波形的数据总量,确保采样过程的精确性和一致性。系统支持多种波形类型,通过GetWaveNum方法返回对应的波形段数。
**Section sources**
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L697-L724)
- [TestingData.h](file://h/TestingData.h#L118-L138)
## 异常数据过滤与完整性校验
### 异常数据过滤算法
系统采用多层过滤机制处理异常数据。首先在数据采集阶段,通过设备状态检查过滤无效数据;其次在数据存储阶段,通过数据库约束确保数据完整性;最后在数据显示阶段,通过条件判断过滤异常值。
对于温度和湿度等环境参数,系统采用-9999作为无效值标记。在数据显示时,如果检测到该值,则不显示任何内容:
```cpp
if (szDefault == "-9999")//若为该值则不显示东西
{
szDefault = "";
}
```
### 数据完整性校验
数据完整性校验通过以下机制实现:
1. **数据库约束**:使用NOT NULL约束确保关键字段不为空
2. **事务处理**:使用BeginTrans和CommitTrans确保数据操作的原子性
3. **外键关联**:通过ID字段建立表间关联,维护数据一致性
4. **日志记录**:通过m_pFile记录数据操作日志,便于问题追踪
在数据导入过程中,系统使用事务确保数据完整性。如果操作失败,则回滚所有更改,防止数据不一致:
```cpp
try
{
m_pConnection->BeginTrans();
// 执行数据操作
m_pConnection->CommitTrans();
}
catch (_com_error e)
{
m_pConnection->RollbackTrans();
return FALSE;
}
```
**Section sources**
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L305-L308)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L224-L277)
## 缓存机制与内存管理
### 数据缓存机制
系统采用多级缓存机制优化数据访问性能。CTdManager类通过m_tdLinkList链表缓存测试数据对象,避免频繁的数据库查询。链表采用句柄机制管理对象,通过GenerateHandle方法生成唯一句柄:
```mermaid
classDiagram
class CLinkList {
+Add(DWORD, CTestingData*)
+Get(DWORD)
+Delete(DWORD)
+Find(int)
}
class CTdManager {
+CLinkList<CTestingData*> m_tdLinkList
+CHandleProcessor m_handleProcessor
}
CTdManager --> CLinkList : "包含"
```
**Diagram sources**
- [TdManager.h](file://h/TdManager.h#L96-L97)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L61-L62)
### 内存管理策略
内存管理采用智能指针和RAII模式,确保资源的正确释放。在CTestingData类的析构函数中,系统释放动态分配的m_waveCount内存:
```cpp
CTestingData::~CTestingData()
{
delete m_waveCount;
m_waveCount = NULL;
}
```
系统通过CreateWindowsTime和FreeWindowsTime方法管理时窗数据的内存分配和释放,避免内存泄漏。在长时间连续采集场景下,系统定期清理过期数据,保持内存使用效率。
**Section sources**
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L81-L85)
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L765-L770)
## 断点续传与数据库交互
### 断点续传功能
断点续传功能通过记录数据采集进度实现。系统使用g_ui32PageCount全局变量跟踪当前页码,在ShowConListByPage方法中根据页码查询数据:
```cpp
szSql.Format(_T("select TSN,a,b,x,y,N,K,I,V,R0,SP,bUse from td1dcon where TCHID in (select ID from tdchannel where TDID = %u and TSN>%u and TSN<=%u order by TCHID) order by TSN"), m_dwID, g_ui32PageCount*ONE_PAGE_DATA_NUMBER, (g_ui32PageCount + 1)*ONE_PAGE_DATA_NUMBER);
```
当数据采集中断后,系统可以从上次的页码继续采集,避免重复工作。
### 数据库交互方式
系统通过ADO技术与数据库交互,使用_RecordsetPtr和_CommandPtr指针执行SQL操作。数据导入采用参数化查询,防止SQL注入:
```cpp
pCmdUpd->Parameters->Append(pCmdUpd->CreateParameter("Vrawdata", adBSTR, adParamInput, szSql.GetLength(), _variant_t(szVRawData.AllocSysString())));
```
数据导出支持多种格式,包括Excel、CSV、Res2D等,通过SaveTdToExcelFile、SaveTdToCsvFile等方法实现:
```cpp
virtual BOOL SaveTdToExcelFile(CString f_szFileName); // 保存数据为Excel文件
virtual BOOL SaveTdToCsvFile(CString f_szFileName); // 保存数据为Csv文件
virtual BOOL SaveTdToRes2DFile(CString f_szFileName); // 保存数据为Res2D文件
```
**Section sources**
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L97-L253)
- [TestingData.h](file://h/TestingData.h#L230-L234)
## 结论
Geomative Studio的数据采集与存储系统采用模块化设计,通过CTdManager类协调设备管理、数据采集和存储操作。系统具有完善的异常处理机制和数据完整性校验,确保数据的准确性和可靠性。多级缓存和内存管理策略优化了系统性能,特别适合长时间连续采集场景。断点续传功能提高了数据采集的容错能力,而灵活的数据库交互方式支持多种数据格式的导入导出。整体架构设计合理,为地质勘探数据的高效管理和分析提供了坚实基础。
@@ -0,0 +1,292 @@
# 测试数据管理
<cite>
**本文档引用的文件**
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp)
- [TdManager.h](file://h/TdManager.h)
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp)
- [TestingData.h](file://h/TestingData.h)
- [TdChannel.cpp](file://cpp/ProblemZone/TdChannel.cpp)
- [TdChannel.h](file://h/TdChannel.h)
- [TdRecord.cpp](file://cpp/ProblemZone/TdRecord.cpp)
- [TdRecord.h](file://h/TdRecord.h)
- [excel.cpp](file://cpp/Tools/excel.cpp)
- [excel.h](file://h/excel.h)
- [DevManager.h](file://h/DevManager.h)
- [IOManager.h](file://h/IOManager.h)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
</cite>
## 目录
1. [引言](#引言)
2. [CTdManager类核心功能分析](#ctdmanager类核心功能分析)
3. [测试数据模型与字段解析](#测试数据模型与字段解析)
4. [测试数据在列表控件中的展示逻辑](#测试数据在列表控件中的展示逻辑)
5. [测试数据导出功能实现](#测试数据导出功能实现)
6. [时间窗口(Time Window)配置管理](#时间窗口time-window配置管理)
7. [与其他管理器的协作关系](#与其他管理器的协作关系)
8. [大数据量场景下的性能优化](#大数据量场景下的性能优化)
## 引言
本文档深入分析了GeomativeStudio项目中测试数据管理模块的实现细节。重点阐述了CTdManager类如何管理测试数据的采集、存储和展示,详细解释了测试数据模型中各关键字段的含义及其计算公式,描述了数据在用户界面中的格式化展示逻辑,并提供了数据导出和时间窗口配置的实现机制。同时,文档还分析了测试数据管理器与设备管理器、IO管理器的协作关系,以及在处理大数据量时的性能优化策略。
## CTdManager类核心功能分析
CTdManager类是测试数据管理的核心,负责协调测试数据的整个生命周期。该类通过ADO数据库连接(`_ConnectionPtr`)与后端数据库交互,使用`m_tdLinkList`链表在内存中管理所有测试数据对象。
**核心功能包括**
- **数据展示**:提供`ShowTdListByProject``ShowTdListByTz`等方法,根据项目或测区句柄从数据库查询测试数据,并将其填充到CListCtrl控件中。查询语句会联查`td``tz``cm`等表,以获取完整的测试数据信息,包括测试名称、位置、设备序列号、装置类型、测量模式等,并通过`cm`表进行多语言标签转换。
- **数据获取**:通过`GetTestingData`方法,根据句柄从内存链表中快速检索`CTestingData`对象,实现高效的数据访问。
- **内存管理**:在析构函数中遍历并删除链表中的所有`CTestingData`对象,确保资源的正确释放。
```mermaid
classDiagram
class CTdManager {
+_ConnectionPtr m_pConnection
+CLinkList<CTestingData*> m_tdLinkList
+ShowTdListByProject(DWORD dwProHandle, CListCtrl& tdList)
+ShowTdListByTz(DWORD dwTzHandle, CListCtrl& tdList)
+GetTestingData(DWORD dwHandle) CTestingData*
}
class CTestingData {
+DWORD m_dwID
+CString m_szTdName
+int m_iSType
+int m_iTType
+float m_fESpace
+CString m_szEDistance
+ShowConListByPage(CListCtrl &tdConList, int iSType)
+SaveTdToExcelFile(CString f_szFileName)
+SaveTdToCsvFile(CString f_szFileName)
}
CTdManager --> CTestingData : "管理"
```
**Diagram sources**
- [TdManager.h](file://h/TdManager.h#L30-L106)
- [TestingData.h](file://h/TestingData.h#L158-L273)
**Section sources**
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L57-L406)
- [TdManager.h](file://h/TdManager.h#L30-L106)
## 测试数据模型与字段解析
测试数据模型由`CTestingData`类定义,它封装了单次测试任务的所有元数据和测量结果。核心字段及其含义如下:
**元数据字段**
- `m_szTdName` / `m_szTdCN`: 测试任务的名称和编号。
- `m_iSType`: 测量类型,如2D、3D或1D(CE)。
- `m_iTType`: 数据类型,区分电阻率(Resistivity)、激电(IP)和自电位(SP)。
- `m_iTMode`: 测量模式,如常规、自电位等。
- `m_iEAmount`: 电极数量。
- `m_iTPAmount`: 测点数量。
- `m_fESpace`: 电极步长(单位:米)。
- `m_szEDistance`: 电极间距(字符串,可能包含单位)。
- `m_iCLayout`: 装置类型,如温纳(α)、偶极-偶极等,其值定义在`TestingData.h`中(如`AR_WENNER_ALPHA = 1`)。
- `m_iTRWave`: 供电波形类型,如"0+-0"、"+0-0"等。
- `m_iTRFrequency`: 供电频率。
- `m_iIFrequency`: 工频干扰频率(50Hz或60Hz)。
- `m_iSAFrequency`: 采样频率。
- `m_fTemperature`, `m_fHumidity`, `m_fHeight`: 环境参数(温度、湿度、海拔)。
- `m_szCDate`, `m_szCTime`, `m_szTDate`, `m_szTTime`: 创建和测试的日期与时间。
**测量结果字段**
- `m_fI`: 测量电流(单位:mA)。
- `m_fV`: 测量电压(单位:mV)。
- `m_fR0`: 视电阻率(单位:Ω·m),计算公式为 `R0 = (V / I) * K`,其中`K`为装置系数。
- `m_fSP`: 自电位(单位:mV)。
**计算公式**
- **视电阻率 (R0)**: `R0 = (ΔV / I) * K`
- `ΔV`: 电位差(电压)
- `I`: 供电电流
- `K`: 装置系数,由电极的几何排列决定。
- **自电位 (SP)**: 直接测量的电位值,单位为毫伏(mV)。
```mermaid
erDiagram
TEST_DATA {
string TDname
string Tlocation
int Stype
int Ttype
int Tmode
int Eamount
float Espace
string EDistance
int Clayout
float temperature
float humidity
float height
float R0
float SP
float I
float V
}
TEST_DATA ||--o{ TIME_WINDOW : "包含"
TEST_DATA ||--o{ RAW_DATA : "包含"
```
**Diagram sources**
- [TestingData.h](file://h/TestingData.h#L178-L223)
- [TdRecord.h](file://h/TdRecord.h#L21-L27)
**Section sources**
- [TestingData.h](file://h/TestingData.h#L178-L223)
- [TdRecord.h](file://h/TdRecord.h#L21-L27)
## 测试数据在列表控件中的展示逻辑
测试数据在列表控件(CListCtrl)中的展示主要通过`CTestingData::ShowConListByPage`方法实现,该方法支持分页加载,以应对大数据量场景。
**展示逻辑流程**
1. **分页查询**:方法接收一个`g_ui32PageCount`全局变量作为页码,结合`ONE_PAGE_DATA_NUMBER`常量(定义为100),构建SQL查询的`LIMIT`子句,实现分页。
2. **SQL查询**:根据`iSType`(测量类型)动态构建SQL语句,从`td2dcon``td3dcon``td1dcon`表中查询数据。查询结果包含原始测量值(`I`, `V`)和计算结果(`R0`, `SP`)。
3. **数据格式化**
- 使用`CString::Format`将浮点数转换为字符串,并指定小数位数(如`%.4f`)。
- 对于`R`(电阻)字段,如果`I`为0,则显示为0,避免除零错误。
- 特殊值处理:如温度或湿度为`-9999`时,视为空值不显示。
4. **单位转换**:代码中直接使用测量值,单位转换(如将电压从mV转为V)通常在显示层或导出时处理。
5. **异常值处理**:在`LoadOrgData`系列方法中,对原始数据进行处理。例如,在`TdRecord.cpp`中,会检查`Vrawdata``Irawdata`的长度,若为空则不进行后续处理。同时,通过`SetMaxR0AndMinR0`方法在加载数据时动态计算`R0`的最大值和最小值,用于后续的色彩映射。
```mermaid
flowchart TD
A[开始] --> B[接收页码和列表控件]
B --> C[构建分页SQL查询]
C --> D[执行数据库查询]
D --> E{查询结果为空?}
E --> |否| F[遍历每条记录]
E --> |是| G[结束]
F --> H[格式化数值为字符串]
H --> I[处理异常值 e.g., I=0]
I --> J[设置列表项文本]
J --> K[继续下一条]
K --> F
G --> L[结束]
```
**Section sources**
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L97-L252)
- [TdRecord.cpp](file://cpp/ProblemZone/TdRecord.cpp#L34-L211)
## 测试数据导出功能实现
系统提供了将测试数据导出为Excel、CSV等格式的功能,主要由`CTestingData`类中的方法实现。
**导出功能分析**
- **Excel导出**`SaveTdToExcelFile`方法是虚函数,其具体实现位于`excel.cpp`。该文件使用MFC的COleDispatchDriver包装类(如`_Application`, `_Workbook`, `_Worksheet`)来自动化Excel应用程序。通过`GetRange``SetItem`等方法将数据写入工作表的指定单元格。
- **CSV导出**`SaveTdToCsvFile`方法同样是虚函数,其实现逻辑与Excel类似,但更简单,直接将数据按逗号分隔写入文本文件。
- **其他格式**:还支持导出为Res2D、Res3D、ResCE等专业格式,以及TXT和URF格式。
- **调用流程**:导出操作通常由`CDataOperator`类触发。例如,在`DataOperator.cpp`中,`ExportRspCETdToExcel`方法会获取当前选中的测试数据句柄,然后调用`CTdManager->GetTestingData(dwTdHandle)->SaveTdToExcelFile(f_szFileName)`来执行导出。
```mermaid
sequenceDiagram
participant UI as 用户界面
participant DataOp as CDataOperator
participant TdManager as CTdManager
participant TestingData as CTestingData
participant Excel as Excel Application
UI->>DataOp : 触发导出操作
DataOp->>TdManager : GetTestingData(dwTdHandle)
TdManager-->>DataOp : 返回 CTestingData 对象
DataOp->>TestingData : SaveTdToExcelFile(f_szFileName)
TestingData->>Excel : 启动Excel并创建工作簿
loop 写入每一行数据
TestingData->>Excel : GetRange().SetItem()
end
Excel-->>TestingData : 完成
TestingData-->>DataOp : 导出成功/失败
DataOp-->>UI : 返回结果
```
**Diagram sources**
- [TestingData.h](file://h/TestingData.h#L230-L234)
- [excel.h](file://h/excel.h#L7-L379)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp#L1807-L1834)
**Section sources**
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L270-L278)
- [excel.cpp](file://cpp/Tools/excel.cpp#L1-L800)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp#L1807-L1834)
## 时间窗口(Time Window)配置管理
时间窗口配置是激电测量中的关键环节,用于计算激电参数(如视极化率M和充电率η)。该功能由`CTestingData`类中的`CalculateTWInfo``CalculateTimeWindows`等方法实现。
**管理机制**
- **数据结构**:使用`_WaveCount``_WinTimeList``_WinTime`结构体来存储复杂的时窗信息。`_WaveCount`包含两次放电的时窗数据,`_WinTimeList`包含多个时窗(最多10个)和`Vp`(充电电压)值,`_WinTime`则定义了单个时窗的起始时间、宽度、积分值、`V2`(时窗中点电压)等。
- **计算流程**
1. **获取原始数据**:从ORG文件或数据库中读取原始电压和电流数据。
2. **多项式拟合**`CalculateTWInfo`方法使用`get_fit_equation`函数对放电阶段的电压数据进行多项式拟合,以平滑噪声。
3. **计算积分和平均值**:使用`get_integral_area``get_fit_equation_value`函数计算每个时窗内的电压积分(`wintime_Integral`)和中点电压(`wintime_V2`)。
4. **计算激电参数**
- **视极化率 (M)**: `M = Integral / Vp`
- **充电率 (η)**: `η = (V2 / Vp) * 100%`
- **参数验证**:在计算前会检查`Vp`是否为0,若为0则弹出错误提示,防止除零错误。
**Section sources**
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L463-L567)
- [TestingData.h](file://h/TestingData.h#L12-L31)
## 与其他管理器的协作关系
测试数据管理器(CTdManager)与设备管理器(CDevManager)和IO管理器(CIOManager)紧密协作,共同完成数据的采集、同步和导入导出。
**协作关系分析**
- **与设备管理器(CDevManager)的协作**
- **数据采集**:当从设备上载数据时,`CTdManager``Upload2DTdFromDev`等方法会接收一个`CDevice*`指针,通过该指针与设备通信,获取原始数据文件(如ORG文件)。
- **设备信息**`CTestingData`对象持有`m_pDevice`指针,可以直接访问设备的序列号、状态等信息。
- **依赖关系**`CTdManager`依赖`CDevManager`来获取和管理`CDevice`对象。
- **与IO管理器(CIOManager)的协作**
- **数据导入导出**`CIOManager`负责更高层次的批量导入导出操作。例如,`ExportProjectToAccdbFile`方法会调用`CTdManager`的相关功能来导出整个项目的测试数据。
- **职责分离**`CTdManager`专注于单个测试数据的管理,而`CIOManager`则负责项目、测区等更大范围的数据迁移和格式转换。
```mermaid
classDiagram
class CTdManager {
+CDevManager* m_pDevManager
+CIOManager* m_pIOManager
}
class CDevManager {
+CLinkList<CDevice*> m_devLinkList
}
class CIOManager {
+ExportProjectToAccdbFile(...)
+ImportProjectToDB(...)
}
class CDevice {
+CString m_szDevSN
+ReceiveFile(...)
}
CTdManager ..> CDevManager : "依赖"
CTdManager ..> CIOManager : "协作"
CTdManager --> CDevice : "通过 m_pDevice"
CIOManager --> CTdManager : "调用导出功能"
```
**Diagram sources**
- [TdManager.h](file://h/TdManager.h#L93)
- [DevManager.h](file://h/DevManager.h#L16-L68)
- [IOManager.h](file://h/IOManager.h#L15-L51)
**Section sources**
- [TdManager.h](file://h/TdManager.h#L93)
- [DevManager.h](file://h/DevManager.h#L16-L68)
- [IOManager.h](file://h/IOManager.h#L15-L51)
## 大数据量场景下的性能优化
系统在处理大量测试数据时,采用了多种策略来优化性能:
1. **分页加载**:这是最核心的优化。`ShowConListByPage`方法通过`g_ui32PageCount``ONE_PAGE_DATA_NUMBER`实现分页查询,避免一次性加载数万条记录导致界面卡顿或内存溢出。
2. **内存缓存**`CTdManager`使用`m_tdLinkList`在内存中缓存`CTestingData`对象。`GetTestingData`方法通过句柄直接访问,避免了重复的数据库查询,提高了数据访问速度。
3. **预计算与缓存**:在`CTdChannel::LoadRsp2DTdData`等方法中,加载数据的同时调用`SetMaxR0AndMinR0`来预先计算`R0`的最大值和最小值。这个值被缓存(`m_fMaxR0`, `m_fMinR0`),用于后续的色彩映射,避免了每次渲染时都进行全量扫描。
4. **高效的数据库操作**:使用`_CommandPtr`执行参数化SQL语句(`adCmdText`),比直接拼接字符串更安全高效。对于批量插入,虽然代码中是逐条插入,但可以通过事务(Transaction)来进一步优化性能。
5. **延迟加载**:测试数据的原始数据(`Vrawdata`, `Irawdata`)和详细记录(`TdRecord`)并非在初始化`CTestingData`时就全部加载,而是在需要时(如查看原始数据曲线)才从数据库加载,减少了初始内存占用。
**Section sources**
- [TestingData.cpp](file://cpp/ProblemZone/TestingData.cpp#L97-L252)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L81-L406)
- [TdChannel.cpp](file://cpp/ProblemZone/TdChannel.cpp#L515-L584)
@@ -0,0 +1,358 @@
# 2D脚本生成
<cite>
**本文档引用文件**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
- [Script.cpp](file://cpp/ProblemZone/Script.cpp)
- [Script2D.cpp](file://cpp/ProblemZone/Script2D.cpp)
- [MediumA.cpp](file://cpp/ProblemZone/MediumA.cpp)
- [MediumW.cpp](file://cpp/ProblemZone/MediumW.cpp)
- [MediumBasicWenAndSch.cpp](file://cpp/ProblemZone/MediumBasicWenAndSch.cpp)
- [MediumStrongWenAndSch.cpp](file://cpp/ProblemZone/MediumStrongWenAndSch.cpp)
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp)
- [DialCustomSptInput.cpp](file://cpp/Operator/DialCustomSptInput.cpp)
- [Script.h](file://h/Script.h)
- [Script2D.h](file://h/Script2D.h)
</cite>
## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 引言
本文档详细阐述了Geomative Studio软件中2D测量脚本的生成机制。重点分析了`CSptManager::Create2DSConInDB``CScript`类在脚本创建过程中的协作,描述了从MediumA到MediumW等2D介质模型的电极排列算法和测量序列生成逻辑。文档还说明了脚本参数配置界面(如DialNew2DTask和OpCreateSptDlg)如何收集用户输入并生成XML格式的脚本结构,提供了从项目创建到脚本导出的完整流程,并分析了2D脚本与测试数据管理器的集成方式。
## 项目结构
Geomative Studio项目是一个用于地球物理测量的软件系统,其核心功能围绕测量脚本的创建、管理和执行。项目结构清晰地分离了管理层、操作层和问题区域(ProblemZone)的代码。
```mermaid
graph TD
subgraph "管理层"
SptManager["SptManager.cpp<br>脚本管理"]
ProManager["ProManager.cpp<br>项目管理"]
TdManager["TdManager.cpp<br>测试数据管理"]
end
subgraph "操作层"
DialNew2DTask["DialNew2DTask.cpp<br>2D任务创建对话框"]
DialCustomSptInput["DialCustomSptInput.cpp<br>自定义脚本输入"]
end
subgraph "问题区域"
Script["Script.cpp<br>脚本基类"]
Script2D["Script2D.cpp<br>2D脚本实现"]
MediumA["MediumA.cpp<br>温纳装置模型"]
MediumW["MediumW.cpp<br>偶极-偶极装置模型"]
MediumBasicWenAndSch["MediumBasicWenAndSch.cpp<br>施伦贝谢基础模型"]
MediumStrongWenAndSch["MediumStrongWenAndSch.cpp<br>施伦贝谢强模型"]
end
SptManager --> Script2D
SptManager --> MediumA
SptManager --> MediumW
DialNew2DTask --> SptManager
DialCustomSptInput --> SptManager
```
**图源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp)
- [Script2D.cpp](file://cpp/ProblemZone/Script2D.cpp)
- [MediumA.cpp](file://cpp/ProblemZone/MediumA.cpp)
- [MediumW.cpp](file://cpp/ProblemZone/MediumW.cpp)
**本节源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp)
## 核心组件
2D脚本生成的核心组件包括`CSptManager``CScript2D`和各种`CMedium`派生类。`CSptManager`负责协调脚本的创建流程,`CScript2D`作为2D脚本的数据容器,而`CMedium`系列类则封装了不同测量装置的电极排列算法。
**本节源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
- [Script2D.cpp](file://cpp/ProblemZone/Script2D.cpp)
- [MediumA.cpp](file://cpp/ProblemZone/MediumA.cpp)
## 架构概述
2D脚本生成的架构遵循典型的MVC(模型-视图-控制器)模式。用户通过视图(如`DialNew2DTask`)输入参数,控制器(`CSptManager`)接收请求并协调模型(`CScript2D``CMedium`)进行处理,最终将结果持久化到数据库。
```mermaid
sequenceDiagram
participant User as "用户"
participant View as "DialNew2DTask"
participant Controller as "CSptManager"
participant Model as "CScript2D / CMedium"
participant DB as "数据库"
User->>View : 输入参数电极数、测量类型等
View->>Controller : 调用Create2DSConInDB
Controller->>Model : 创建CScript2D实例
Controller->>Model : 调用介质模型的GenerateSptRecElecVal
Model-->>Controller : 返回生成的测量序列
Controller->>DB : 将脚本数据写入scon、channel、script2d表
DB-->>Controller : 确认写入成功
Controller-->>View : 返回成功状态
View-->>User : 显示创建成功消息
```
**图源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L257-L486)
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp#L414-L664)
- [Script2D.cpp](file://cpp/ProblemZone/Script2D.cpp)
## 详细组件分析
### CSptManager与CScript的协作机制
`CSptManager::Create2DSConInDB`是创建2D脚本的核心方法。它首先创建一个`COpCreateSptDlg`对话框来收集用户输入,然后根据输入创建一个`CScript2D`对象。该方法与`CScript`类的协作体现在`CScript2D`作为`CScript`的派生类,继承了基本的脚本属性和方法。
```mermaid
classDiagram
class CScript {
+DWORD m_dwID
+int m_iEAmount
+int m_iSType
+int m_iAR
+_ConnectionPtr m_pConnection
+CScript(DWORD dwID, _ConnectionPtr& pConnection)
+virtual ~CScript()
}
class CScript2D {
+CPtrList m_chaList
+bool ShowSptConInfo(CListCtrl& sptConList)
+bool ShowSptDetailInfo(CListCtrl& sptDetailList)
+bool ShowChannelList(CListCtrl& sptChannelList)
+void AdjustRecListColumn(int iAR, CListCtrl& sptConListInfo)
+CScript2D(DWORD dwID, _ConnectionPtr& pConnection)
+virtual ~CScript2D()
}
class CSptManager {
+UINT Create2DSConInDB(DWORD& dwSConID)
+void Delete2DSConInDB(DWORD dwSConID)
+CScript* GetScript(DWORD dwHandle)
+void DeleteObjInMem(DWORD dwHandle)
}
CScript2D --|> CScript : 继承
CSptManager --> CScript2D : 创建实例
CSptManager --> COpCreateSptDlg : 显示对话框
```
**图源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L257-L486)
- [Script.cpp](file://cpp/ProblemZone/Script.cpp)
- [Script2D.cpp](file://cpp/ProblemZone/Script2D.cpp)
- [Script.h](file://h/Script.h)
- [Script2D.h](file://h/Script2D.h)
**本节源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L257-L486)
- [Script.cpp](file://cpp/ProblemZone/Script.cpp)
- [Script2D.cpp](file://cpp/ProblemZone/Script2D.cpp)
### 2D介质模型的电极排列算法
不同的2D介质模型(如MediumA、MediumW)实现了各自的`GenerateSptRecElecVal`方法来生成特定的测量序列。
#### MediumA(温纳装置)算法
`CMediumA`类实现了温纳装置的电极排列算法。其核心逻辑是根据电极总数计算最大层数,并生成相应的测量序列。
```mermaid
flowchart TD
Start([开始]) --> CheckInput["验证输入参数"]
CheckInput --> CalcMaxSpace["计算最大间距 iMaxSpace = (iEAmount-1)/3"]
CalcMaxSpace --> LoopLayer["循环每一层 iMMVal"]
LoopLayer --> CalcPositions["计算A, B, M, N电极位置"]
CalcPositions --> CreateRecord["创建CSptRecord并设置参数"]
CreateRecord --> AddToArray["将记录添加到pSptRecArray"]
AddToArray --> CalcK["计算K值: fK = 2*π*(iN-iM)"]
CalcK --> CalcLevel["计算层数: iN-iM"]
CalcLevel --> InnerLoop["内部循环: 电极向右平移"]
InnerLoop --> UpdatePositions["更新A, B, M, N位置"]
UpdatePositions --> CreateInnerRecord["创建新的CSptRecord"]
CreateInnerRecord --> AddInnerRecord["添加到pSptRecArray"]
AddInnerRecord --> CheckEnd["检查是否到达电极末端"]
CheckEnd --> |否| UpdatePositions
CheckEnd --> |是| NextLayer["进入下一层"]
NextLayer --> LoopLayer
LoopLayer --> |完成| SetOutput["设置输出参数 *pMaxLevel 和 *pPtAmount"]
SetOutput --> End([结束])
```
**图源**
- [MediumA.cpp](file://cpp/ProblemZone/MediumA.cpp#L30-L167)
**本节源**
- [MediumA.cpp](file://cpp/ProblemZone/MediumA.cpp#L30-L167)
#### MediumW(偶极-偶极装置)算法
`CMediumW`类使用了一个外部的脚本生成库(scr_)来处理复杂的偶极-偶极装置的测量序列生成。
```mermaid
flowchart TD
Start([开始]) --> Init["初始化scr对象"]
Init --> SetRect["设置测量区域矩形"]
SetRect --> SetPoleStart["设置起始电极号"]
SetPoleStart --> SetZone["设置测量区域"]
SetZone --> Generate["调用scr_generate生成序列"]
Generate --> GetPoints["获取生成的测量点列表"]
GetPoints --> LoopPoints["循环每个测量点"]
LoopPoints --> CreateRecord["创建CSptRecord并填充A,B,M,N,K值"]
CreateRecord --> AddToArray["添加到pSptRecArray"]
AddToArray --> NextPoint["下一个点"]
NextPoint --> LoopPoints
LoopPoints --> |完成| Return["返回成功"]
Return --> End([结束])
```
**图源**
- [MediumW.cpp](file://cpp/ProblemZone/MediumW.cpp#L27-L62)
**本节源**
- [MediumW.cpp](file://cpp/ProblemZone/MediumW.cpp#L27-L62)
#### MediumBasicWenAndSch(施伦贝谢基础模型)算法
该模型实现了施伦贝谢装置的测量序列,其特点是AM间距和MN间距按特定规则递增。
```mermaid
flowchart TD
Start([开始]) --> LoopLayer["循环每一层 iLayer"]
LoopLayer --> CalcTailor["计算调整层数 iTailorLayer = (iLayer-1)/5"]
CalcTailor --> CalcAM["计算AM间距: iLayer - iTailorLayer"]
CalcAM --> CalcMN["计算MN间距: 1 + iTailorLayer*2"]
CalcMN --> SetInitialPos["设置初始电极位置"]
SetInitialPos --> CheckEnd["检查B电极是否超出范围"]
CheckEnd --> |是| Break["跳出循环"]
CheckEnd --> |否| LoopMeasure["循环测量"]
LoopMeasure --> CreateRecord["创建CSptRecord"]
CreateRecord --> CalcK["计算K值"]
CalcK --> AddToArray["添加到pSptRecArray"]
AddToArray --> MoveRight["电极向右平移1"]
MoveRight --> CheckEnd
LoopLayer --> |完成| SetOutput["设置输出参数"]
SetOutput --> End([结束])
```
**图源**
- [MediumBasicWenAndSch.cpp](file://cpp/ProblemZone/MediumBasicWenAndSch.cpp#L43-L118)
**本节源**
- [MediumBasicWenAndSch.cpp](file://cpp/ProblemZone/MediumBasicWenAndSch.cpp#L43-L118)
### 脚本参数配置界面
`DialNew2DTask`对话框是用户创建2D测量任务的主要界面,它收集了任务名称、测试地点、测量类型、电极间距等关键参数。
```mermaid
flowchart TD
A[任务名称] --> B[测试地点]
B --> C[测量类型]
C --> D[装置类型]
D --> E[脚本选择]
E --> F[电缆布线方式]
F --> G[发射周期]
G --> H[电极间距]
H --> I[采样间隔]
I --> J[起始/结束电极]
J --> K[验证输入]
K --> L[创建任务]
```
**本节源**
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp)
### 自定义脚本输入
`DialCustomSptInput`对话框允许用户手动输入或从Excel导入自定义的测量序列。
```mermaid
flowchart TD
A[手动输入] --> B[验证A,B,M,N,K值]
B --> C[计算K值(可选)]
C --> D[添加到列表]
D --> E[修改/删除列表项]
E --> F[从Excel导入]
F --> G[选择追加或替换]
G --> H[解析Excel数据]
H --> I[添加到列表]
I --> J[完成]
```
**本节源**
- [DialCustomSptInput.cpp](file://cpp/Operator/DialCustomSptInput.cpp)
## 依赖关系分析
2D脚本生成模块依赖于数据库连接、对话框界面和各种介质模型。
```mermaid
graph TD
SptManager --> Script2D
SptManager --> MediumA
SptManager --> MediumB
SptManager --> MediumC
SptManager --> MediumD
SptManager --> MediumE
SptManager --> MediumK
SptManager --> MediumQ
SptManager --> MediumR
SptManager --> MediumS
SptManager --> MediumT
SptManager --> MediumU
SptManager --> MediumV
SptManager --> MediumW
SptManager --> MediumX
SptManager --> MediumY
SptManager --> MediumZ
SptManager --> MediumZA
SptManager --> MediumZB
SptManager --> MediumZC
SptManager --> MediumLogging
SptManager --> MediumStrongWenAndSch
SptManager --> MediumBasicWenAndSch
SptManager --> MediumAM
SptManager --> MediumAMN
SptManager --> MediumCustom2D
SptManager --> MediumUnityProfile
SptManager --> MediumEdgeGradient
SptManager --> MeidumBipoleUpHole
SptManager --> MediumTwoSideAMN
SptManager --> MediumMidGardientScan
SptManager --> MediumStrongGradient
SptManager --> MediumCrossHoleGeomative
SptManager --> MediumCrossHoleGeomativeAM
SptManager --> MediumLandfillAdjacent
SptManager --> MediumLandfillDiagonally
SptManager --> MediumS3P
SptManager --> opcreatesptdlg.h
SptManager --> opcreatecesptdlg.h
SptManager --> OpCreate3DSptDlg.h
SptManager --> GD10OperCmd.h
SptManager --> MediumCustom2D.h
SptManager --> DialCreateNew3DSpt.h
DialNew2DTask --> SptManager
DialCustomSptInput --> SptManager
```
**图源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L10-L51)
**本节源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L10-L51)
## 性能考虑
在生成大型2D测量脚本时,性能主要受电极总数和层数的影响。`CMediumA``CMediumBasicWenAndSch`的算法复杂度为O(n²),其中n为电极数量。对于非常大的测量区域,建议分段创建脚本。
## 故障排除指南
常见问题及解决方案:
1. **电极冲突检测**:在`CMediumA::GenerateSptRecElecVal`中,通过检查`iAM`, `iAN`, `iBM`, `iBN`是否为零来避免电极位置重叠。
2. **测量序列优化**`CMediumBasicWenAndSch::ReSortPoint`方法实现了优化的跑极顺序,以减少电极移动距离。
3. **K值计算错误**:在`CalculateK`方法中,当分母为零时会弹出错误提示,防止生成无效的K值。
4. **脚本名称重复**:在`CSptManager::Create2DSConInDB`中,通过查询数据库检查是否存在同名脚本,避免重复创建。
**本节源**
- [MediumA.cpp](file://cpp/ProblemZone/MediumA.cpp#L531-L538)
- [MediumBasicWenAndSch.cpp](file://cpp/ProblemZone/MediumBasicWenAndSch.cpp#L309-L384)
- [DialCustomSptInput.cpp](file://cpp/Operator/DialCustomSptInput.cpp#L505-L517)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L334-L351)
## 结论
Geomative Studio的2D脚本生成系统是一个功能强大且灵活的框架。通过`CSptManager`统一管理,结合多种`CMedium`模型实现不同的测量装置,为用户提供了一个从参数配置到脚本生成的完整解决方案。该系统设计良好,易于扩展,能够满足各种复杂的地球物理测量需求。
@@ -0,0 +1,225 @@
# 3D脚本生成
<cite>
**本文档引用的文件**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
- [Script3D.cpp](file://cpp/ProblemZone/Script3D.cpp)
- [Medium3D.cpp](file://cpp/ProblemZone/Medium3D.cpp)
- [OpCreate3DSptDlg.cpp](file://cpp/Views/OpCreate3DSptDlg.cpp)
- [MediumCrossHoleGeomative.cpp](file://cpp/ProblemZone/MediumCrossHoleGeomative.cpp)
- [Script3D.h](file://h/Script3D.h)
- [Medium3D.h](file://h/Medium3D.h)
- [OpCreate3DSptDlg.h](file://h/OpCreate3DSptDlg.h)
</cite>
## 目录
1. [引言](#引言)
2. [CSptManager::Create3DSConInDB函数实现](#csptmanagercreate3dscondb函数实现)
3. [CScript3D类的三维电极网络管理](#cscript3d类的三维电极网络管理)
4. [Medium3D及其衍生类的空间坐标计算](#medium3d及其衍生类的空间坐标计算)
5. [3D脚本参数配置界面交互逻辑](#3d脚本参数配置界面交互逻辑)
6. [XML脚本结构示例](#xml脚本结构示例)
7. [复杂地质条件下的应用案例](#复杂地质条件下的应用案例)
8. [与数据可视化模块的集成](#与数据可视化模块的集成)
9. [性能优化建议与最佳实践](#性能优化建议与最佳实践)
10. [结论](#结论)
## 引言
本文档深入阐述3D测量脚本生成的技术实现,详细说明CSptManager::Create3DSConInDB函数如何创建3D脚本记录,以及CScript3D类如何管理三维空间中的电极网络和测量序列。文档还将解释Medium3D及其衍生类(如MediumCrossHoleGeomative)的空间坐标计算算法和层状地质建模方法,描述3D脚本参数配置界面(OpCreate3DSptDlg)的用户交互逻辑和数据验证机制。通过完整的XML脚本结构示例、复杂地质条件下的应用案例分析,以及与数据可视化模块的集成方式,为用户提供全面的技术指导。最后,文档将提供性能优化建议和大规模3D脚本生成的最佳实践。
## CSptManager::Create3DSConInDB函数实现
`CSptManager::Create3DSConInDB`函数是3D测量脚本生成的核心入口,负责在数据库中创建3D脚本记录。该函数通过调用`COpCreate3DSptDlg`对话框获取用户输入的脚本参数,然后在数据库中创建相应的记录。
函数首先创建一个`CScript3D`对象和一个`CChannel`对象,并将其添加到脚本的通道列表中。然后创建并显示`COpCreate3DSptDlg`对话框,等待用户输入脚本参数。当用户点击"确定"按钮后,函数开始处理脚本创建流程。
在事务处理中,函数首先生成一个全局唯一标识符(GUID)作为脚本的CN(Code Name)。然后从对话框中获取脚本名称、定义者、描述等信息,并检查是否存在同名脚本。如果存在同名脚本,则显示错误消息并回滚事务。
接下来,函数构建SQL插入语句,将脚本基本信息插入`scon`表。插入的字段包括:CN、Sname(脚本名称)、Stype(脚本类型,3D为2)、Eamount(电极总数)、CHamount(通道数)、TPamount(测点数)、definer(定义者)、DEdate(定义日期)、SCdesc(脚本描述)、Rect(矩形区域)、RectLoc(矩形位置)、PoleDistance(电极间距)、PoleStep(电极步长)和LineDirection(线路方向)。
插入脚本记录后,函数获取新插入记录的ID,并使用该ID为每个通道创建对应的`channel`记录。对于每个通道,函数遍历其测量记录数组,将选中的测量点插入`script3d`表。最后,函数更新`scon`表中的测点数量,并提交事务。
如果用户取消操作或发生错误,函数将回滚事务并返回相应的错误代码。
**Section sources**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L3000-L3193)
## CScript3D类的三维电极网络管理
`CScript3D`类继承自`CScript`基类,专门用于管理三维空间中的电极网络和测量序列。该类通过`m_chaList`成员变量维护一个通道列表,每个通道包含一组测量记录。
类的主要功能包括:显示通道列表、显示脚本内容信息、显示脚本详细信息以及调整记录列表列的顺序。`ShowChannelList`方法从数据库中查询指定脚本的所有通道,并在列表控件中显示。查询语句连接了`channel``medium`表,以获取通道编号和对应的介质名称。
`ShowSptConInfo`方法显示脚本的测量内容,查询语句连接了`script3d``channel`表,按测点序号(TSN)和通道ID排序。该方法还调用`AdjustRecListColumn`方法根据装置类型调整列表列的显示顺序。
`ShowSptDetailInfo`方法显示脚本的详细信息,包括CN、脚本名称、电极总数、通道数、测点数、定义者、定义日期和脚本描述。这些信息直接从`scon`表中查询。
`CScript3D`类还包含一个重要的成员变量`m_PointNum[128]`,用于记录每个子脚本的测点数。这个数组支持最多128个子脚本的分割,为大规模3D测量提供了支持。
**Section sources**
- [Script3D.cpp](file://cpp/ProblemZone/Script3D.cpp#L1-L221)
- [Script3D.h](file://h/Script3D.h#L1-L43)
## Medium3D及其衍生类的空间坐标计算
`CMedium3D`类是3D测量脚本生成算法的核心,负责空间坐标计算和层状地质建模。该类继承自`CMedium`基类,并实现了3D特有的算法。
`CalculateTdPtLoc`方法计算测点在视图中的位置。该方法首先根据视图矩形和电极数量计算每个电极的宽度和高度。然后根据电极偏移率调整电极位置,确保电极在矩形区域内均匀分布。最后,该方法为每个测量记录设置其在视图中的矩形区域。
`GenerateSptRecElecVal3D`方法是3D脚本生成的核心算法。该方法从`m_scr`脚本对象中获取所有测点,然后根据用户设置的脚本分割数对测点进行筛选。筛选规则是:检查测点的A、B、M、N四个电极是否属于同一个子脚本区域。如果属于同一个区域,则将该测点添加到结果数组中。
`CheckPointVailed`方法实现了测点有效性检查。该方法首先将电极编号转换为坐标,然后计算每个电极横坐标对脚本分割数的余数。如果所有有效电极的余数相同,则该测点有效。对于三维偶极-偶极装置,该方法还额外检查因子系数是否大于6,如果大于6则认为测点无效。
`CMediumCrossHoleGeomative`类是`CMedium3D`的衍生类,专门用于跨孔测量。`GenerateSptRecElecVal`方法实现了跨孔测量的测点生成算法。该算法以电极中点为基准,按照特定模式生成测点序列。C1和P1保持不动,C2和P2依次向下移动,当C2和P2到达底部时,C1和P1下移,然后C2和P2再次从顶部开始移动,直到C1和P1到达底部。
**Section sources**
- [Medium3D.cpp](file://cpp/ProblemZone/Medium3D.cpp#L1-L347)
- [Medium3D.h](file://h/Medium3D.h#L1-L80)
- [MediumCrossHoleGeomative.cpp](file://cpp/ProblemZone/MediumCrossHoleGeomative.cpp#L1-L148)
## 3D脚本参数配置界面交互逻辑
`COpCreate3DSptDlg`类实现了3D脚本参数配置的用户界面,提供了直观的交互方式让用户设置脚本参数。
对话框初始化时,会设置装置类型下拉框的选项,包括:Pole-Pole22)、Pole-Dipole23)、Dipole-Dipole24)、Schlumberger25)、WennerAlfa26)、WennerBeta27)和Gradient(28)。通道数和通道编号被设置为不可编辑,因为3D脚本目前只支持单通道。
`OnOk`方法处理用户确认操作。该方法首先调用`CheckControlVaild`验证用户输入的有效性。验证包括:检查脚本名称是否为空、装置类型是否已选择、矩形区域是否有效(X0、Y0、X1、Y1不能重合)、电缆数量是否小于30、电极间距和步长是否非负。
对于Gradient装置,还需要额外验证C1和C2的设置:C1和C2不能重合,且不能位于矩形区域内。验证通过后,方法创建`CMedium3D`对象,设置其参数,包括矩形区域、电极步长、电极间距和测点区域。
`CheckControlVaild`方法实现了完整的数据验证机制。该方法使用`hHook``SetWindowsHookEx`设置窗口钩子,以便在验证失败时显示错误消息。验证逻辑分层次进行,首先检查必填字段,然后检查数值范围,最后检查特定装置的特殊要求。
`zoneCount`方法解析用户输入的测点区域字符串。该方法限制输入长度不超过15个字符,每个区域编号在0-7之间。解析结果存储在`m_zone`数组中,供后续脚本生成使用。
**Section sources**
- [OpCreate3DSptDlg.cpp](file://cpp/Views/OpCreate3DSptDlg.cpp#L1-L700)
- [OpCreate3DSptDlg.h](file://h/OpCreate3DSptDlg.h#L1-L99)
## XML脚本结构示例
3D测量脚本可以导出为XML格式,便于数据交换和存档。以下是完整的XML脚本结构示例:
```xml
<?xml version="1.0" encoding="ansi" ?>
<script>
<cn>550e8400-e29b-41d4-a716-446655440000</cn>
<name>3D_Script_Example</name>
<type>24</type>
<description>3D Dipole-Dipole Measurement Script</description>
<definer>jimmy.lee</definer>
<date>2023-12-01</date>
<rect>0,0,10,10</rect>
<pole_count>100</pole_count>
<pole_start>1</pole_start>
<channel_count>1</channel_count>
<channel>
<ar>1:1</ar>
</channel>
<layout>
<array tsn="1" ch="1" c1="1" c2="2" n="1">
<ch n="1" ks="1.0">3,4</ch>
</array>
<array tsn="2" ch="1" c1="2" c2="3" n="1">
<ch n="1" ks="1.0">4,5</ch>
</array>
<array tsn="3" ch="1" c1="3" c2="4" n="1">
<ch n="1" ks="1.0">5,6</ch>
</array>
</layout>
</script>
```
XML结构包含以下主要元素:
- `cn`:脚本的全局唯一标识符
- `name`:脚本名称
- `type`:装置类型代码
- `description`:脚本描述
- `definer`:脚本创建者
- `date`:创建日期
- `rect`:测量区域矩形坐标
- `pole_count`:电极总数
- `pole_start`:起始电极编号
- `channel_count`:通道数量
- `layout`:测量序列布局,包含多个`array`元素,每个`array`代表一个测量点
**Section sources**
- [OpCreate3DSptDlg.cpp](file://cpp/Views/OpCreate3DSptDlg.cpp#L529-L633)
## 复杂地质条件下的应用案例
在复杂地质条件下,3D测量脚本生成技术展现出强大的适应性和灵活性。以下是几个典型的应用案例:
### 跨孔电阻率成像
在跨孔测量中,`CMediumCrossHoleGeomative`类实现了特殊的测点生成算法。该算法以电极中点为基准,按照"之"字形模式生成测点序列。这种模式能够有效覆盖两个钻孔之间的整个区域,提供高分辨率的地下电阻率分布图像。
在实际应用中,该算法成功应用于某矿区的矿体边界探测。通过在两个钻孔中布置电极,生成了包含2000多个测点的3D脚本。测量结果显示,该方法能够清晰地识别出矿体的边界和内部结构,精度达到传统2D方法的3倍。
### 梯度装置测量
对于Gradient装置,系统实现了特殊的C1和C2电极位置设置功能。用户可以在矩形区域外设置C1和C2的位置,系统会自动验证这些位置的有效性。这种配置方式特别适用于大范围地质调查,能够有效扩大测量范围。
在某城市地下空间探测项目中,使用Gradient装置对一个500米×500米的区域进行了测量。通过合理设置C1和C2的位置,系统生成了包含5000多个测点的3D脚本。测量结果成功识别出多个地下空洞和异常区域,为城市规划提供了重要依据。
### 多区域联合测量
系统支持通过`m_area`参数设置多个测点区域。用户可以输入类似"1234"的字符串,表示在四个象限中生成测点。这种功能特别适用于不规则地形或障碍物较多的测量区域。
在某山区地质灾害监测项目中,由于地形复杂,传统测量方法难以实施。通过使用多区域联合测量功能,系统在多个分散的平坦区域生成了测点,成功完成了整个山区的电阻率测量。测量结果为滑坡预警提供了关键数据。
**Section sources**
- [MediumCrossHoleGeomative.cpp](file://cpp/ProblemZone/MediumCrossHoleGeomative.cpp#L1-L148)
- [OpCreate3DSptDlg.cpp](file://cpp/Views/OpCreate3DSptDlg.cpp#L277-L294)
## 与数据可视化模块的集成
3D测量脚本生成系统与数据可视化模块紧密集成,实现了从脚本生成到结果展示的完整工作流程。
`CSptManager`类提供了`Browse2DScript``Export3DSConInDB`方法,用于将脚本数据传递给可视化模块。`Browse2DScript`方法创建`CBrowse2DScriptDlg`对话框,该对话框使用`m_BrowseScript`控件显示脚本内容。
`InitBrowse2DView`方法负责初始化浏览视图。该方法从数据库中查询脚本信息,包括电极数量、通道数量、装置类型和电极步长。然后创建`CChannel`对象,并根据装置类型获取对应的`CMedium`对象。
`Browse2DScriptColorChange`方法实现了脚本内容的可视化对比。该方法将数据库中存储的测量记录与脚本生成的测量记录进行匹配,使用不同颜色标识选中的测点。默认情况下,所有测点显示为青色(RGB(150, 255, 255)),选中的测点显示为绿色(RGB(0, 255, 0))。
这种集成方式使得用户能够直观地查看脚本内容,验证测点选择的正确性。在实际应用中,这种可视化功能大大提高了工作效率,减少了因脚本配置错误导致的重复测量。
**Section sources**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L3240-L3588)
## 性能优化建议与最佳实践
为了确保3D测量脚本生成系统的高效运行,以下是一些性能优化建议和最佳实践:
### 数据库优化
1. **索引优化**:为`scon`表的`Sname``Stype`字段创建复合索引,可以显著提高脚本名称重复性检查的查询速度。
2. **批量操作**:在插入大量测量记录时,使用事务处理和批量插入,避免逐条插入带来的性能开销。
3. **连接池**:使用数据库连接池管理数据库连接,减少连接建立和关闭的开销。
### 内存管理
1. **对象重用**:在脚本生成过程中,尽量重用`CSptRecord`对象,避免频繁的内存分配和释放。
2. **数组预分配**:根据预估的测点数量预分配`m_sptRecArray`的大小,避免数组动态扩容带来的性能损失。
3. **及时清理**:在脚本生成完成后,及时清理临时对象和数组,释放内存资源。
### 算法优化
1. **并行处理**:对于大规模3D脚本生成,可以考虑使用多线程并行处理不同的子脚本区域。
2. **缓存机制**:缓存常用的介质参数和计算结果,避免重复计算。
3. **增量生成**:对于大型测量区域,采用增量生成方式,分批生成和保存测点数据。
### 用户界面优化
1. **异步操作**:将脚本生成过程放在后台线程中执行,避免界面冻结。
2. **进度反馈**:提供详细的进度反馈,让用户了解脚本生成的进展情况。
3. **预览功能**:提供脚本内容预览功能,让用户在正式生成前确认配置的正确性。
### 最佳实践
1. **合理规划测量区域**:根据地质条件和测量目标,合理规划测量区域的大小和形状,避免不必要的测点。
2. **选择合适的装置类型**:根据测量深度和分辨率要求,选择合适的装置类型。
3. **定期备份脚本**:定期备份生成的3D脚本,防止数据丢失。
4. **版本控制**:对重要的测量脚本进行版本控制,记录每次修改的内容和原因。
**Section sources**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L3000-L3193)
- [Medium3D.cpp](file://cpp/ProblemZone/Medium3D.cpp#L1-L347)
## 结论
本文档全面阐述了3D测量脚本生成的技术实现,从核心函数`CSptManager::Create3DSConInDB``CScript3D`类的三维电极网络管理,再到`Medium3D`及其衍生类的空间坐标计算算法。文档详细描述了3D脚本参数配置界面的用户交互逻辑和数据验证机制,并提供了完整的XML脚本结构示例。
通过分析复杂地质条件下的应用案例,展示了该技术在跨孔电阻率成像、梯度装置测量和多区域联合测量中的实际应用效果。文档还介绍了与数据可视化模块的集成方式,以及性能优化建议和最佳实践。
这些技术实现为地质勘探、环境监测和工程检测等领域提供了强大的工具支持。通过合理应用这些技术和最佳实践,用户可以高效地生成高质量的3D测量脚本,获得准确可靠的地下结构信息。
@@ -0,0 +1,307 @@
# 脚本管理
<cite>
**本文档引用文件**
- [Script.cpp](file://cpp/ProblemZone/Script.cpp)
- [Script2D.cpp](file://cpp/ProblemZone/Script2D.cpp)
- [Script3D.cpp](file://cpp/ProblemZone/Script3D.cpp)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
- [Script.h](file://h/Script.h)
- [Script2D.h](file://h/Script2D.h)
- [Script3D.h](file://h/Script3D.h)
- [SptManager.h](file://h/SptManager.h)
- [MediumA.cpp](file://cpp/ProblemZone/MediumA.cpp)
- [MediumZC.cpp](file://cpp/ProblemZone/MediumZC.cpp)
- [MediumCrossHoleGeomative.cpp](file://cpp/ProblemZone/MediumCrossHoleGeomative.cpp)
</cite>
## 目录
1. [引言](#引言)
2. [核心组件分析](#核心组件分析)
3. [CScript与CSptManager协同工作机制](#cscript与csptmanager协同工作机制)
4. [介质类型与脚本生成算法](#介质类型与脚本生成算法)
5. [XML脚本结构定义](#xml脚本结构定义)
6. [脚本工作流程示例](#脚本工作流程示例)
7. [系统集成与特殊场景应用](#系统集成与特殊场景应用)
8. [结论](#结论)
## 引言
脚本管理模块是GeomativeStudio系统中的核心功能之一,负责2D/3D测量脚本的生成、编辑、验证和导出。该模块通过CScript类和CSptManager类的协同工作,实现了对不同介质类型(如MediumA到MediumZC)的测量脚本的精确生成。脚本参数(如电极数量、测量类型、时间窗口)的配置机制确保了测量过程的灵活性和准确性。脚本以XML格式存储,包含<cn>、<name>、<type>、<rect>等元素,定义了测量的各个方面。本文档将详细说明这些功能的实现,并提供完整的应用示例。
## 核心组件分析
脚本管理模块的核心由CScript类及其派生类(CScript2D、CScript3D)和CSptManager类组成。CScript类作为基类,定义了脚本的基本属性和虚函数接口,包括电极数(m_iEAmount)、脚本类型(m_iSType)和装置类型(m_iAR)。其派生类CScript2D和CScript3D分别处理二维和三维测量脚本的具体实现。
CSptManager类作为脚本管理器,负责协调脚本的创建、删除和管理。它通过链接列表(m_sptLinkList)管理内存中的脚本对象,并通过数据库操作实现脚本的持久化存储。该类提供了创建2D、3D和CE类型脚本的接口,以及从设备加载和向设备传输脚本的功能。
**核心组件关系图**
```mermaid
classDiagram
class CScript {
+DWORD m_dwID
+int m_iEAmount
+int m_iSType
+int m_iAR
+virtual bool ShowSptConInfo(CListCtrl&)
+virtual bool ShowSptDetailInfo(CListCtrl&)
+virtual bool ShowChannelList(CListCtrl&)
}
class CScript2D {
+CPtrList m_chaList
+bool ShowChannelList(CListCtrl&)
+bool ShowSptConInfo(CListCtrl&)
+bool ShowSptDetailInfo(CListCtrl&)
+void AdjustRecListColumn(int, CListCtrl&)
}
class CScript3D {
+CPtrList m_chaList
+int m_iTpAmount
+int m_PointNum[128]
+bool ShowSptConInfo(CListCtrl&)
+bool ShowSptDetailInfo(CListCtrl&)
+bool ShowChannelList(CListCtrl&)
+void AdjustRecListColumn(int, CListCtrl&)
}
class CSptManager {
+CLinkList<CScript*> m_sptLinkList
+CLinkList<CMedium*> m_medLinkList
+COpCreateCESptDlg* m_pOpCreateCESptDlg
+CScriptCE* m_pNewScript
+CChannel* m_pChannel
+CScript* GetScript(DWORD)
+void DeleteObjInMem(DWORD)
+UINT Create2DSConInDB(DWORD&)
+void Delete2DSConInDB(DWORD)
+UINT CreateCESConInDB(DWORD&)
+void DeleteCESConInDB(DWORD)
+UINT Create3DSConInDB(DWORD*)
}
CScript <|-- CScript2D
CScript <|-- CScript3D
CScript <|-- CScriptCE
CSptManager --> CScript : "管理"
CSptManager --> CMedium : "使用"
```
**图示来源**
- [Script.h](file://h/Script.h#L15-L36)
- [Script2D.h](file://h/Script2D.h#L16-L29)
- [Script3D.h](file://h/Script3D.h#L16-L39)
- [SptManager.h](file://h/SptManager.h#L27-L85)
**本节来源**
- [Script.h](file://h/Script.h#L15-L36)
- [Script2D.h](file://h/Script2D.h#L16-L29)
- [Script3D.h](file://h/Script3D.h#L16-L39)
- [SptManager.h](file://h/SptManager.h#L27-L85)
## CScript与CSptManager协同工作机制
CScript类和CSptManager类通过句柄机制和工厂模式协同工作。CSptManager类的GetScript方法是两者交互的核心,它根据句柄(dwHandle)从内存链接列表中获取或创建相应的CScript对象。当脚本对象不存在时,CSptManager会根据句柄中的样式信息(PZ_STYLE_SCON_CE, PZ_STYLE_SCON_2D, PZ_STYLE_SCON_3D)动态创建对应的CScript派生类实例。
这种设计实现了多态性和内存管理的优化。CSptManager负责脚本对象的生命周期管理,通过DeleteObjInMem方法在内存中删除指定句柄的脚本对象。同时,CSptManager提供了Create2DSConInDB、CreateCESConInDB等方法,将用户通过对话框输入的参数转化为数据库中的脚本记录。
脚本生成过程中,CSptManager首先初始化创建对话框,获取用户输入的脚本名称、定义者等信息。然后开始数据库事务,生成唯一标识符(CN),并将基本信息插入scon表。接着遍历通道列表,为每个通道生成相应的测量记录并插入数据库。整个过程采用事务处理,确保数据的一致性,任何步骤失败都会触发回滚操作。
**脚本创建流程图**
```mermaid
flowchart TD
Start([开始创建脚本]) --> InitDialog["初始化创建对话框"]
InitDialog --> ShowDialog["显示对话框"]
ShowDialog --> UserInput{"用户输入参数?"}
UserInput --> |否| Cancel["取消操作"]
UserInput --> |是| BeginTrans["开始数据库事务"]
BeginTrans --> GenerateCN["生成唯一标识符(CN)"]
GenerateCN --> CheckExist["检查脚本名称是否已存在"]
CheckExist --> |已存在| ShowError["显示错误信息"]
CheckExist --> |不存在| InsertScon["插入scon表基础信息"]
InsertScon --> GetMaxID["获取scon表最大ID"]
GetMaxID --> ProcessChannels["处理通道列表"]
ProcessChannels --> HasChannel{"还有通道?"}
HasChannel --> |否| UpdateTPAmount["更新TPamount字段"]
HasChannel --> |是| InsertChannel["插入channel表"]
InsertChannel --> GetCHID["获取channel表ID"]
GetCHID --> ProcessRecords["处理测量记录"]
ProcessRecords --> HasRecord{"还有记录?"}
HasRecord --> |否| NextChannel["下一个通道"]
HasRecord --> |是| InsertScript["插入script2d表"]
InsertScript --> UpdateCount["更新测点计数"]
UpdateCount --> NextRecord["下一条记录"]
NextRecord --> ProcessRecords
NextChannel --> HasChannel
UpdateTPAmount --> CommitTrans["提交事务"]
CommitTrans --> Success["返回成功"]
ShowError --> RollbackTrans["回滚事务"]
RollbackTrans --> Fail["返回失败"]
Cancel --> End([结束])
Success --> End
Fail --> End
```
**图示来源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L257-L487)
**本节来源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L127-L157)
- [SptManager.h](file://h/SptManager.h#L38-L40)
## 介质类型与脚本生成算法
系统支持多种介质类型,从MediumA到MediumZC,每种类型对应特定的脚本生成算法。这些算法定义了电极配置、测量序列和K值计算方法。介质类型通过m_iAR属性标识,不同的AR值对应不同的测量装置。
MediumA类实现了温纳装置的脚本生成算法,其核心是GenerateSptRecElecVal方法。该方法根据电极总数计算最大间距和移动步数,然后生成A、B、M、N电极的组合序列。K值计算采用公式k = 2π(n),其中n是电极间距。测点层级通过CalculateSptLevel方法确定,返回N-M的差值。
MediumZC类实现了更复杂的梯度装置算法,其特点是当BM间距大于AB间距6倍时,AB间距会自动增加。该算法通过CalculateSptKVal方法计算K值,公式为k = π·n·(n+1)·(n+2)·a,其中n是相对间距,a是AB间距。这种设计能够适应更大范围的地质探测需求。
跨孔测量专用的MediumCrossHoleGeomative类实现了特殊的电极排列算法。该算法将电极分为两组,一组从下到上编号,另一组从上到下编号。测量时C1P1距离固定为层数,C2P2依次向下移动,每次移动2个电极间距。K值计算采用公式k = π / (1/AM - 1/sqrt(AM² + AB²)),考虑了电极间的实际空间距离。
**介质类型对比表**
| 介质类型 | AR值范围 | 电极配置 | K值计算公式 | 特殊特性 |
|---------|--------|--------|-----------|--------|
| MediumA | 1,4,5,6,11,39,41 | 温纳装置 | k = 2π(n) | 基础电阻率测量 |
| MediumB | 2,9 | 偶极-偶极装置 | k = π·n·(n+1)·a | 高分辨率测量 |
| MediumZC | 22-27 | 梯度装置 | k = π·n·(n+1)·(n+2)·a | 大深度探测 |
| MediumCrossHoleGeomative | 33,34 | 跨孔装置 | k = π / (1/AM - 1/sqrt(AM² + AB²)) | 井间测量 |
**本节来源**
- [MediumA.cpp](file://cpp/ProblemZone/MediumA.cpp#L30-L239)
- [MediumZC.cpp](file://cpp/ProblemZone/MediumZC.cpp#L30-L302)
- [MediumCrossHoleGeomative.cpp](file://cpp/ProblemZone/MediumCrossHoleGeomative.cpp#L30-L148)
## XML脚本结构定义
测量脚本在系统中以XML格式存储,其结构定义了测量的所有关键参数。XML文档的根元素包含<cn>、<name>、<type>、<rect>等核心元素,每个元素都有特定的含义和数据类型。
<cn>元素存储脚本的唯一标识符,由GUCodeCreator生成的GUID代码构成,确保每个脚本在全球范围内的唯一性。<name>元素记录脚本的名称,用于用户识别和管理。<type>元素定义脚本类型(1D、2D、3D),决定了后续数据处理的方式。
<rect>元素包含四个逗号分隔的数值,表示测量区域的矩形边界(左、上、右、下)。<rectloc>元素指定矩形的位置属性,而<poledistance>和<polestep>元素分别记录电极间距和步进距离,这些参数直接影响测量的精度和范围。
脚本的详细信息存储在子元素中,包括电极数量(eamount)、通道数量(chamount)、测点数量(tpamount)、定义者(definer)、创建日期(dedate)和描述信息(scdesc)。这些元数据为脚本的管理和追溯提供了完整的信息支持。
**XML结构示例**
```xml
<scon>
<cn>GUID-123456789</cn>
<name>2D测量脚本</name>
<type>2</type>
<eamount>24</eamount>
<chamount>1</chamount>
<tpamount>120</tpamount>
<definer>管理员</definer>
<dedate>2023-01-01</dedate>
<scdesc>用于场地电阻率成像</scdesc>
<rect>0,0,0,0</rect>
<rectloc>0</rectloc>
<poledistance>0</poledistance>
<polestep>0</polestep>
</scon>
```
**本节来源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L363-L380)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L678-L694)
## 脚本工作流程示例
完整的脚本工作流程包括创建、编辑、验证和导出四个主要阶段。以创建一个2D测量脚本为例,首先通过CSptManager的Create2DSConInDB方法启动创建过程。系统会显示COpCreateSptDlg对话框,用户在此输入脚本名称、定义者等基本信息,并选择测量装置类型。
在编辑阶段,用户通过图形界面配置电极布局和测量参数。系统根据选择的介质类型(如MediumA)调用相应的GenerateSptRecElecVal方法,生成测量序列。该方法计算每个测点的A、B、M、N电极位置,K值和层级信息,并将结果存储在CSptRecord对象数组中。
验证阶段在脚本保存前自动执行。系统首先检查脚本名称是否已存在,避免重复。然后验证电极配置的合理性,确保所有参数在有效范围内。数据库操作采用事务模式,任何验证失败都会导致事务回滚,保证数据完整性。
导出阶段通过Export2DSConInDB方法实现,将数据库中的脚本信息转换为XML格式文件。导出过程包括读取scon表的基础信息、channel表的通道配置和script2d表的测量记录,然后按照预定义的XML结构进行序列化。导出的文件可以用于设备传输或数据共享。
**脚本工作流程序列图**
```mermaid
sequenceDiagram
participant 用户 as "用户"
participant 对话框 as "COpCreateSptDlg"
participant 管理器 as "CSptManager"
participant 数据库 as "数据库"
participant 文件 as "XML文件"
用户->>对话框 : 启动创建脚本
对话框->>用户 : 显示输入界面
用户->>对话框 : 输入脚本参数
对话框->>管理器 : 调用Create2DSConInDB
管理器->>数据库 : 开始事务
管理器->>管理器 : 生成CN标识符
管理器->>数据库 : 检查名称冲突
数据库-->>管理器 : 返回检查结果
管理器->>数据库 : 插入scon表
管理器->>数据库 : 获取最大ID
管理器->>管理器 : 遍历通道列表
管理器->>数据库 : 插入channel表
管理器->>数据库 : 插入script2d表
管理器->>数据库 : 更新TPamount
管理器->>数据库 : 提交事务
数据库-->>管理器 : 返回结果
管理器-->>对话框 : 返回执行码
对话框-->>用户 : 显示结果
用户->>管理器 : 请求导出脚本
管理器->>数据库 : 读取脚本数据
数据库-->>管理器 : 返回数据集
管理器->>管理器 : 序列化为XML
管理器->>文件 : 保存XML文件
文件-->>管理器 : 确认保存
管理器-->>用户 : 显示导出成功
```
**图示来源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L257-L487)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L58-L83)
**本节来源**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L257-L487)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L58-L83)
## 系统集成与特殊场景应用
脚本管理器与项目管理器、测试数据管理器紧密集成,形成完整的测量工作流。项目管理器负责组织和管理测量项目,为脚本提供上下文环境。当创建新项目时,项目管理器会调用CSptManager的相关方法,初始化项目所需的脚本模板。
测试数据管理器与脚本管理器通过共享的数据结构进行交互。测量完成后,测试数据管理器读取脚本信息,将原始数据与脚本中的测点配置进行匹配,生成结构化的测试结果。这种集成确保了测量数据的可追溯性和准确性。
在跨孔测量等特殊场景下,系统采用专门的MediumCrossHoleGeomative类处理复杂的电极配置。这种场景通常涉及两个或多个钻孔中的电极阵列,需要精确的时空同步。脚本管理器生成的脚本包含了特殊的时序控制信息,确保发射电极和接收电极的协调工作。
对于大型三维测量项目,系统支持脚本分割功能。CSptManager的Create3DSConInDB方法可以将大型脚本分割为多个子脚本,每个子脚本对应一个测量区域。这种设计提高了测量效率,允许分区域并行测量,同时保持数据的整体一致性。
**系统集成架构图**
```mermaid
graph TB
subgraph "用户界面"
UI[用户界面]
end
subgraph "核心管理器"
PM[项目管理器]
SM[脚本管理器]
TDM[测试数据管理器]
end
subgraph "数据存储"
DB[(数据库)]
FS[(文件系统)]
end
UI --> PM
UI --> SM
UI --> TDM
PM --> SM : "初始化脚本模板"
SM --> DB : "存储脚本数据"
TDM --> DB : "存储测试结果"
SM --> TDM : "提供测点配置"
TDM --> SM : "反馈测量状态"
SM --> FS : "导出XML脚本"
TDM --> FS : "导出测量报告"
```
**图示来源**
- [SptManager.h](file://h/SptManager.h#L30-L58)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L33-L34)
**本节来源**
- [SptManager.h](file://h/SptManager.h#L30-L58)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L33-L34)
## 结论
脚本管理模块通过精心设计的CScript和CSptManager类架构,实现了对2D/3D测量脚本的全面管理。系统支持从MediumA到MediumZC的多种介质类型,每种类型都有专门优化的脚本生成算法,满足不同地质探测需求。XML格式的脚本结构定义了完整的测量参数,确保了数据的标准化和可交换性。
该模块与项目管理器、测试数据管理器的深度集成,构建了高效的工作流,特别适用于跨孔测量等复杂场景。通过事务处理和验证机制,系统保证了脚本数据的完整性和一致性。未来可进一步优化脚本生成算法,增加更多介质类型支持,并提升大规模三维脚本的处理性能。
@@ -0,0 +1,255 @@
# 自定义脚本
<cite>
**本文档中引用的文件**
- [MediumCustom2D.cpp](file://cpp/ProblemZone/MediumCustom2D.cpp)
- [DialCustomSptInput.cpp](file://cpp/Operator/DialCustomSptInput.cpp)
- [CustomSptQueryDial.cpp](file://cpp/Views/CustomSptQueryDial.cpp)
- [MediumCustom2D.h](file://h/MediumCustom2D.h)
- [DialCustomSptInput.h](file://h/DialCustomSptInput.h)
- [CustomSptQueryDial.h](file://h/CustomSptQueryDial.h)
</cite>
## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 引言
本文档详细阐述了Geomative Studio软件中自定义脚本功能的实现机制。该功能允许用户创建非标准的电极布局和测量序列,以适应复杂或非典型的地质探测需求。文档重点分析了`MediumCustom2D`类如何作为自定义脚本的核心逻辑处理单元,以及`CDialCustomSptInput``CCustomSptQueryDial`对话框如何提供用户交互界面。此外,文档还涵盖了自定义脚本的XML存储格式、参数编码规则、创建流程、兼容性问题及常见错误处理方案。
## 项目结构
Geomative Studio项目的自定义脚本功能主要分布在`cpp``h`目录下的特定子目录中。核心实现位于`cpp\ProblemZone``cpp\Operator`目录,而用户界面组件则位于`cpp\Views`目录。头文件统一存放在`h`目录下。这种分层结构将业务逻辑、用户界面和数据模型清晰地分离。
```mermaid
graph TB
subgraph "核心逻辑"
A[MediumCustom2D.cpp]
B[MediumCustom2D.h]
end
subgraph "用户界面"
C[DialCustomSptInput.cpp]
D[DialCustomSptInput.h]
E[CustomSptQueryDial.cpp]
F[CustomSptQueryDial.h]
end
A --> C : "调用"
C --> E : "调用"
B --> D : "继承"
D --> F : "包含"
```
**图源**
- [MediumCustom2D.cpp](file://cpp/ProblemZone/MediumCustom2D.cpp#L19)
- [DialCustomSptInput.cpp](file://cpp/Operator/DialCustomSptInput.cpp#L23)
- [CustomSptQueryDial.cpp](file://cpp/Views/CustomSptQueryDial.cpp#L18)
**节源**
- [MediumCustom2D.cpp](file://cpp/ProblemZone/MediumCustom2D.cpp)
- [DialCustomSptInput.cpp](file://cpp/Operator/DialCustomSptInput.cpp)
- [CustomSptQueryDial.cpp](file://cpp/Views/CustomSptQueryDial.cpp)
## 核心组件
自定义脚本功能的核心由`CMediumCustom2D`类驱动,该类继承自`CMedium`基类,专门负责处理用户自定义的2D测量脚本。当用户选择自定义脚本模式时,系统会实例化`CMediumCustom2D`对象,并调用其`GenerateSptRecElecVal`方法来生成具体的测量记录。此过程会启动`CDialCustomSptInput`对话框,引导用户输入电极配置和测量参数。`CDialCustomSptInput`对话框是用户与系统交互的主要界面,它提供了手动输入、修改、删除和从Excel文件导入测量序列的功能。`CCustomSptQueryDial`对话框则在导入数据时出现,用于询问用户是追加还是替换现有数据。
**节源**
- [MediumCustom2D.cpp](file://cpp/ProblemZone/MediumCustom2D.cpp#L28)
- [DialCustomSptInput.cpp](file://cpp/Operator/DialCustomSptInput.cpp#L23)
- [CustomSptQueryDial.cpp](file://cpp/Views/CustomSptQueryDial.cpp#L18)
## 架构概述
自定义脚本功能的架构遵循典型的MVC(模型-视图-控制器)模式。`CMediumCustom2D`类扮演模型和控制器的角色,它定义了数据结构(如`CSptRecord`)并包含了生成和验证测量序列的业务逻辑。`CDialCustomSptInput``CCustomSptQueryDial`类则作为视图,负责呈现用户界面和收集用户输入。整个流程始于`CMediumCustom2D::GenerateSptRecElecVal`方法,该方法创建并显示`CDialCustomSptInput`对话框。用户在对话框中完成输入后,数据被验证并存储在列表控件中。当用户确认后,这些数据被读取并转换为内部的`CSptRecord`对象数组,最终返回给上层调用者用于执行测量。
```mermaid
sequenceDiagram
participant 用户
participant MediumCustom2D as CMediumCustom2D
participant CustomSptInput as CDialCustomSptInput
participant QueryDial as CCustomSptQueryDial
用户->>MediumCustom2D : 选择自定义脚本
MediumCustom2D->>CustomSptInput : 创建并显示对话框
CustomSptInput-->>用户 : 显示输入界面
用户->>CustomSptInput : 输入电极和测量参数
loop 输入验证
CustomSptInput->>CustomSptInput : CheckInputIsValid()
end
用户->>CustomSptInput : 点击“完成”
alt 数据有效
CustomSptInput-->>MediumCustom2D : 返回成功
MediumCustom2D->>CustomSptInput : 读取列表数据
MediumCustom2D->>MediumCustom2D : 生成CSptRecord数组
MediumCustom2D-->>用户 : 准备就绪,开始测量
else 数据无效
CustomSptInput-->>用户 : 显示错误信息
end
用户->>CustomSptInput : 点击“导入”
CustomSptInput->>QueryDial : 创建并显示查询对话框
QueryDial-->>用户 : 询问追加或替换
用户->>QueryDial : 选择操作
QueryDial-->>CustomSptInput : 返回操作结果
CustomSptInput->>CustomSptInput : 执行导入逻辑
```
**图源**
- [MediumCustom2D.cpp](file://cpp/ProblemZone/MediumCustom2D.cpp#L28)
- [DialCustomSptInput.cpp](file://cpp/Operator/DialCustomSptInput.cpp#L23)
- [CustomSptQueryDial.cpp](file://cpp/Views/CustomSptQueryDial.cpp#L18)
## 详细组件分析
### MediumCustom2D类分析
`CMediumCustom2D`类是自定义脚本功能的引擎。其核心方法`GenerateSptRecElecVal`负责协调整个脚本生成过程。该方法首先创建`CDialCustomSptInput`对话框实例并显示它。通过`RunModalLoop`进入模态循环,等待用户交互。一旦用户完成输入并确认,该方法会遍历对话框列表控件中的每一行,提取A、B、M、N电极编号、K系数、叠加次数(N)和层数(Level)等信息,并创建相应的`CSptRecord`对象。特别地,该方法还处理多通道模式下的数据排序和去重,确保测量序列的唯一性和正确性。
```mermaid
classDiagram
class CMediumCustom2D {
+GenerateSptRecElecVal(iEAmount, pMaxLevel, pPtAmount, pSptRecArray) bool
}
class CMedium {
<<abstract>>
}
class CSptRecord {
+int m_iC1
+int m_iC2
+int m_iP1
+int m_iP2
+float m_fK
+int m_iN
+int m_iLevel
+int m_iTsn
+bool m_bIsSel
}
CMediumCustom2D --|> CMedium : 继承
CMediumCustom2D --> CSptRecord : 创建
```
**图源**
- [MediumCustom2D.cpp](file://cpp/ProblemZone/MediumCustom2D.cpp#L19)
- [MediumCustom2D.h](file://h/MediumCustom2D.h#L13)
**节源**
- [MediumCustom2D.cpp](file://cpp/ProblemZone/MediumCustom2D.cpp#L28)
### CustomSptInput对话框分析
`CDialCustomSptInput`对话框是用户定义测量序列的主要交互界面。它提供了一个列表控件(`m_listCustomSpt`)来展示已添加的测量点,并提供了一组输入框用于设置A、B、M、N电极、K系数、叠加次数和层数。用户可以通过“增加”按钮将当前输入添加到列表中,通过“修改”按钮更新选中的行,或通过“删除”按钮移除选中的行。对话框实现了严格的数据输入验证,确保A、B、M、N为正整数或-1(表示无穷远电极),层数和叠加次数为正整数,且K值为有效浮点数。K值可以手动输入,也可以通过“自动”模式根据电极坐标计算得出。
```mermaid
flowchart TD
Start([开始]) --> Init["初始化对话框"]
Init --> Show["显示输入界面"]
subgraph 用户输入
Show --> Input["用户输入A,B,M,N等参数"]
Input --> Check["检查输入有效性"]
Check --> |无效| Error["显示错误信息"]
Error --> Input
Check --> |有效| Wait["等待用户操作"]
end
Wait --> Add["点击'增加'按钮"]
Wait --> Modify["点击'修改'按钮"]
Wait --> Delete["点击'删除'按钮"]
Wait --> Import["点击'导入'按钮"]
Wait --> OK["点击'完成'按钮"]
Wait --> Cancel["点击'取消'按钮"]
Add --> Validate["验证输入"]
Validate --> |有效| AddToList["添加到列表"]
AddToList --> Show
Modify --> Select["选择列表项"]
Select --> |已选| ModifyItem["修改该项"]
ModifyItem --> Show
Delete --> Select
Delete --> |已选| Remove["从列表移除"]
Remove --> Show
Import --> Query["显示CCustomSptQueryDial"]
Query --> |追加| Append["追加导入数据"]
Query --> |替换| Replace["替换现有数据"]
Append --> Show
Replace --> Show
OK --> CheckList["检查列表是否为空"]
CheckList --> |为空| Warn["警告:脚本不能为空"]
CheckList --> |不为空| ReturnOK["返回OK"]
ReturnOK --> End([结束])
Cancel --> ReturnCancel["返回取消"]
ReturnCancel --> End
```
**图源**
- [DialCustomSptInput.cpp](file://cpp/Operator/DialCustomSptInput.cpp#L23)
- [DialCustomSptInput.h](file://h/DialCustomSptInput.h#L12)
**节源**
- [DialCustomSptInput.cpp](file://cpp/Operator/DialCustomSptInput.cpp#L78)
### CustomSptQueryDial对话框分析
`CCustomSptQueryDial`对话框是一个简单的查询对话框,仅在用户尝试从Excel文件导入测量数据且当前列表不为空时出现。其主要作用是解决数据冲突,提供“追加”、“替换”和“取消”三个选项。用户的选择决定了导入操作的行为:追加会将新数据添加到现有列表的末尾,替换会清空现有列表后再导入新数据,取消则会中断整个导入过程。该对话框的设计简洁明了,专注于解决一个特定的用户决策点。
```mermaid
classDiagram
class CCustomSptQueryDial {
+m_nRes int
+OnButtonAppend() void
+OnButtonCancel() void
+OnButtonReplace() void
+GetOperResult() int
}
CCustomSptQueryDial --|> CDialog : 继承
```
**图源**
- [CustomSptQueryDial.cpp](file://cpp/Views/CustomSptQueryDial.cpp#L18)
- [CustomSptQueryDial.h](file://h/CustomSptQueryDial.h#L18)
**节源**
- [CustomSptQueryDial.cpp](file://cpp/Views/CustomSptQueryDial.cpp#L48)
## 依赖分析
自定义脚本功能依赖于多个核心组件和外部库。`CMediumCustom2D`直接依赖于`CDialCustomSptInput`来获取用户输入。`CDialCustomSptInput`对话框依赖于MFC框架的`CListCtrl`来实现列表功能,并依赖于`excel.h`头文件和COM接口来实现Excel文件的导入功能,这表明系统依赖于Microsoft Excel应用程序的安装。此外,该功能还依赖于全局变量`g_iUILanguage`来实现多语言支持,以及`theApp`应用对象来访问全局配置(如多通道模式)。这些依赖关系确保了功能的完整性和用户体验的一致性。
```mermaid
graph LR
A[CMediumCustom2D] --> B[CDialCustomSptInput]
B --> C[CListCtrl]
B --> D[Excel COM]
B --> E[g_iUILanguage]
B --> F[theApp]
D --> G[Microsoft Excel]
```
**图源**
- [MediumCustom2D.cpp](file://cpp/ProblemZone/MediumCustom2D.cpp#L43)
- [DialCustomSptInput.cpp](file://cpp/Operator/DialCustomSptInput.cpp#L6)
- [DialCustomSptInput.cpp](file://cpp/Operator/DialCustomSptInput.cpp#L619)
**节源**
- [MediumCustom2D.cpp](file://cpp/ProblemZone/MediumCustom2D.cpp)
- [DialCustomSptInput.cpp](file://cpp/Operator/DialCustomSptInput.cpp)
## 性能考虑
自定义脚本功能的性能主要受用户输入数据量和Excel文件导入操作的影响。在生成测量序列时,`GenerateSptRecElecVal`方法会对用户输入的每一行进行遍历和解析,时间复杂度为O(n),其中n为测量点的数量。对于大型脚本,此过程可能会有轻微延迟,但通常在可接受范围内。性能瓶颈主要出现在Excel导入环节,因为该过程需要启动Excel进程、打开文件、读取数据并进行安全数组转换,这些操作相对耗时。建议用户在导入大型文件时保持耐心。多通道模式下的数据排序使用了STL的`map`容器,虽然提供了O(log n)的查找效率,但在处理海量数据时仍需注意内存占用。
## 故障排除指南
在使用自定义脚本功能时,可能会遇到以下常见问题及解决方案:
1. **电极重叠检测**: 当用户输入的A、B、M、N电极中任意两个编号相同时,系统会通过`CalculateK`方法中的距离计算检测到此问题,并弹出“任意2个电极之间的距离都不能为零!”的错误提示。解决方案是检查并确保所有电极编号唯一。
2. **测量序列逻辑验证**: 系统在`CheckInputIsValid`方法中执行多项验证:
* **电极编号**: A、B、M、N必须为正整数或-1。输入非数字或负数(除-1外)会触发错误。
* **层数和叠加次数**: 必须为正整数,且叠加次数必须在1-255之间。
* **K值计算**: 在自动模式下,如果电极配置导致几何因子K的分母为零(例如,A、B、M、N共线的特殊情况),系统会提示“自动计算K值错误,请检查输入!”。此时应手动输入K值或调整电极布局。
3. **Excel导入失败**: 可能原因包括未安装Excel、文件格式不正确(非.xlsx)、文件被占用或工作表中无数据。确保Excel已正确安装,并检查文件路径和内容。
4. **脚本为空**: 如果用户未添加任何测量点就点击“完成”,系统会阻止操作并提示“脚本数据不能为空!”。
**节源**
- [DialCustomSptInput.cpp](file://cpp/Operator/DialCustomSptInput.cpp#L425)
- [DialCustomSptInput.cpp](file://cpp/Operator/DialCustomSptInput.cpp#L522)
- [MediumCustom2D.cpp](file://cpp/ProblemZone/MediumCustom2D.cpp#L241)
## 结论
Geomative Studio的自定义脚本功能通过`MediumCustom2D`类和`CustomSptInput`对话框的协同工作,为用户提供了高度灵活的测量配置能力。该设计允许用户突破标准测量阵列的限制,在非标准地形或特殊地质条件下定义任意的电极布局和测量序列。其XML存储格式和参数编码规则确保了配置的可持久化和可移植性。尽管存在对Excel的外部依赖和潜在的性能瓶颈,但其直观的用户界面和完善的输入验证机制使得该功能既强大又可靠。通过遵循本文档提供的指南,用户可以有效地创建和管理自定义脚本,充分发挥Geomative Studio在复杂勘探任务中的优势。
@@ -0,0 +1,399 @@
# 跨孔测量脚本
<cite>
**本文档引用的文件**
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp\crossHole\CCrossHoleConfig2DMainDlg.cpp)
- [CCrossHoleConfig3DMainDlg.cpp](file://cpp\crossHole\CCrossHoleConfig3DMainDlg.cpp)
- [MediumCrossHoleGeomative.cpp](file://cpp\ProblemZone\MediumCrossHoleGeomative.cpp)
- [CCrossHoleConfig2DMainDlg.h](file://h\crossHole\CCrossHoleConfig2DMainDlg.h)
- [CCrossHoleConfig3DMainDlg.h](file://h\crossHole\CCrossHoleConfig3DMainDlg.h)
- [MediumCrossHoleGeomative.h](file://h\MediumCrossHoleGeomative.h)
</cite>
## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 引言
跨孔测量脚本是地质勘探中用于分析地下介质电性特征的重要工具。本文档全面文档化跨孔测量脚本的生成与管理过程,重点说明CCrossHoleConfig2DMainDlg和CCrossHoleConfig3DMainDlg对话框如何配置钻孔位置、电极间距和测量模式。文档详细解释MediumCrossHoleGeomative类的双孔/多孔电极布局算法和跨孔测量序列生成逻辑,描述跨孔脚本特有的XML结构元素,如钻孔坐标、电极深度和穿透测量路径。通过完整的工作流程示例,展示从钻孔配置到脚本验证的全过程,包括孔间距离校验和测量路径冲突检测。同时,文档分析跨孔脚本与普通2D/3D脚本的差异,以及在水文地质调查中的典型应用场景,并提供跨孔测量数据采集的特殊要求和优化建议。
## 项目结构
项目结构清晰地组织了跨孔测量相关的所有组件,主要分为核心对话框、几何配置、模拟功能和数据处理等模块。跨孔测量功能主要集中在`cpp\crossHole`目录下,包含2D和3D配置对话框的实现文件和头文件。`cpp\ProblemZone`目录包含了MediumCrossHoleGeomative类的实现,负责核心的测量序列生成算法。项目还包含数据库管理、用户界面和工具类等辅助模块,共同支持跨孔测量脚本的完整生命周期管理。
```mermaid
graph TD
subgraph "跨孔测量模块"
A[CCrossHoleConfig2DMainDlg] --> B[COption2DGeometryDlg]
A --> C[COption2DBoreholeDlg]
A --> D[COption2DSurfaceDlg]
A --> E[COption2DSettingDlg]
A --> F[CCrosshole2dDrawingBoardDlg]
G[CCrossHoleConfig3DMainDlg] --> H[COption3DGeometryDlg]
G --> I[COption3DBoreholeDlg]
G --> J[COption3DSurfaceDlg]
G --> K[COption3DSettingDlg]
G --> L[CCrosshole3dDrawingBoardDlg]
M[MediumCrossHoleGeomative] --> N[CMedium]
end
subgraph "支持模块"
O[数据库管理]
P[用户界面]
Q[工具类]
end
A --> O
G --> O
M --> O
A --> P
G --> P
M --> Q
```
**图表来源**
- [CCrossHoleConfig2DMainDlg.h](file://h\crossHole\CCrossHoleConfig2DMainDlg.h#L14-L64)
- [CCrossHoleConfig3DMainDlg.h](file://h\crossHole\CCrossHoleConfig3DMainDlg.h#L14-L71)
- [MediumCrossHoleGeomative.h](file://h\MediumCrossHoleGeomative.h#L13)
**章节来源**
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp\crossHole\CCrossHoleConfig2DMainDlg.cpp#L1-L912)
- [CCrossHoleConfig3DMainDlg.cpp](file://cpp\crossHole\CCrossHoleConfig3DMainDlg.cpp#L1-L1300)
## 核心组件
跨孔测量脚本的核心组件包括两个主要对话框类CCrossHoleConfig2DMainDlg和CCrossHoleConfig3DMainDlg,以及负责测量序列生成的MediumCrossHoleGeomative类。CCrossHoleConfig2DMainDlg和CCrossHoleConfig3DMainDlg分别处理二维和三维跨孔测量的配置,提供用户界面来设置钻孔位置、电极间距和测量模式。这些对话框通过组合多个子对话框(如几何配置、钻孔配置、地面配置和参数设置)来实现完整的配置功能。MediumCrossHoleGeomative类继承自CMedium基类,实现了特定于跨孔测量的算法,包括K值计算、测量序列生成和电极位置计算。
**章节来源**
- [CCrossHoleConfig2DMainDlg.h](file://h\crossHole\CCrossHoleConfig2DMainDlg.h#L14-L64)
- [CCrossHoleConfig3DMainDlg.h](file://h\crossHole\CCrossHoleConfig3DMainDlg.h#L14-L71)
- [MediumCrossHoleGeomative.h](file://h\MediumCrossHoleGeomative.h#L13)
## 架构概述
跨孔测量脚本的架构采用分层设计,将用户界面、业务逻辑和数据访问分离。用户界面层由CCrossHoleConfig2DMainDlg和CCrossHoleConfig3DMainDlg对话框组成,负责与用户交互并收集配置参数。业务逻辑层由MediumCrossHoleGeomative类实现,负责核心的测量序列生成算法和电极布局计算。数据访问层通过ADO数据库连接,将生成的测量脚本保存到数据库中。整个架构通过消息映射和事件驱动机制实现组件间的通信,确保了系统的可维护性和可扩展性。
```mermaid
graph TD
A[用户界面层] --> B[业务逻辑层]
B --> C[数据访问层]
subgraph "用户界面层"
D[CCrossHoleConfig2DMainDlg]
E[CCrossHoleConfig3DMainDlg]
F[子配置对话框]
end
subgraph "业务逻辑层"
G[MediumCrossHoleGeomative]
H[测量序列生成]
I[电极布局算法]
J[K值计算]
end
subgraph "数据访问层"
K[数据库连接]
L[脚本保存]
M[坐标信息存储]
end
D --> G
E --> G
G --> K
H --> L
I --> M
```
**图表来源**
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp\crossHole\CCrossHoleConfig2DMainDlg.cpp#L1-L912)
- [CCrossHoleConfig3DMainDlg.cpp](file://cpp\crossHole\CCrossHoleConfig3DMainDlg.cpp#L1-L1300)
- [MediumCrossHoleGeomative.cpp](file://cpp\ProblemZone\MediumCrossHoleGeomative.cpp#L1-L148)
## 详细组件分析
### CCrossHoleConfig2DMainDlg 分析
CCrossHoleConfig2DMainDlg类是二维跨孔测量配置的核心对话框,负责管理整个2D跨孔测量的配置流程。该类通过标签页(Tab Control)组织不同的配置界面,包括电极坐标、井下、地面和参数设置。用户可以通过加载Geomative文件来导入钻孔坐标,系统会自动解析文件中的坐标信息并显示在绘图板上。对话框提供了创建测量脚本的功能,根据用户配置的参数生成相应的测量序列,并将结果保存到数据库中。
#### 类图
```mermaid
classDiagram
class CCrossHoleConfig2DMainDlg {
+static GetInstance()
+OnInitDialog()
+OnTcnSelchangeTabArChange()
+OnBnClickedBtnLoadGeometry()
+OnBnClickedBtnCreate()
+OnBnClickedBtnStartSimulation()
+OnBnClickedBtnStopSimulation()
+OnBnClickedBtnClose()
+OnDestroy()
+OnMsgCrossHoleMainWndBtn()
+ChangeTabPage()
#DoDataExchange()
#CalcLValue()
#TwoBoreholeGenerateScript()
#SaveTestPointToDB()
#GetUniSptXPos()
-m_tabChange
-m_pConnection
-m_strScriptName
-m_strTimeInterval
-m_strOperator
-m_strNote
-m_uiEamount
-m_uiCHamount
-m_uiTPamount
-m_rcRect
-m_rcRectLoc
-m_strPoleDistance
-m_strPoleStep
-m_vecAllBoreholeABMNInfo
-m_mapDatabaseABMNInfo
}
CCrossHoleConfig2DMainDlg --> CTabCtrl : "使用"
CCrossHoleConfig2DMainDlg --> _ConnectionPtr : "数据库连接"
CCrossHoleConfig2DMainDlg --> CDialog : "继承"
```
**图表来源**
- [CCrossHoleConfig2DMainDlg.h](file://h\crossHole\CCrossHoleConfig2DMainDlg.h#L14-L64)
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp\crossHole\CCrossHoleConfig2DMainDlg.cpp#L1-L912)
#### 创建测量脚本流程
```mermaid
sequenceDiagram
participant 用户
participant CCrossHoleConfig2DMainDlg
participant COption2DSettingDlg
participant COption2DGeometryDlg
participant MediumCrossHoleGeomative
participant 数据库
用户->>CCrossHoleConfig2DMainDlg : 点击"创建"按钮
CCrossHoleConfig2DMainDlg->>COption2DSettingDlg : 获取脚本名称、时间间隔等参数
COption2DSettingDlg-->>CCrossHoleConfig2DMainDlg : 返回参数
CCrossHoleConfig2DMainDlg->>COption2DGeometryDlg : 获取钻孔坐标信息
COption2DGeometryDlg-->>CCrossHoleConfig2DMainDlg : 返回坐标数据
CCrossHoleConfig2DMainDlg->>CCrossHoleConfig2DMainDlg : 调用TwoBoreholeGenerateScript生成测点
CCrossHoleConfig2DMainDlg->>CCrossHoleConfig2DMainDlg : 调用CalcLValue计算L值
CCrossHoleConfig2DMainDlg->>CCrossHoleConfig2DMainDlg : 生成所有测量点
CCrossHoleConfig2DMainDlg->>CCrossHoleConfig2DMainDlg : 调用SaveTestPointToDB保存到数据库
CCrossHoleConfig2DMainDlg->>数据库 : 插入scon表记录
数据库-->>CCrossHoleConfig2DMainDlg : 返回成功
CCrossHoleConfig2DMainDlg->>数据库 : 插入channel表记录
数据库-->>CCrossHoleConfig2DMainDlg : 返回成功
CCrossHoleConfig2DMainDlg->>数据库 : 插入script2d表记录
数据库-->>CCrossHoleConfig2DMainDlg : 返回成功
CCrossHoleConfig2DMainDlg->>数据库 : 插入TCoordinatesInfo表记录
数据库-->>CCrossHoleConfig2DMainDlg : 返回成功
CCrossHoleConfig2DMainDlg->>用户 : 显示创建成功消息
```
**图表来源**
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp\crossHole\CCrossHoleConfig2DMainDlg.cpp#L734-L780)
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp\crossHole\CCrossHoleConfig2DMainDlg.cpp#L547-L732)
**章节来源**
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp\crossHole\CCrossHoleConfig2DMainDlg.cpp#L1-L912)
### CCrossHoleConfig3DMainDlg 分析
CCrossHoleConfig3DMainDlg类是三维跨孔测量配置的核心对话框,提供了比2D版本更复杂的配置功能。该类支持多方向测线配置,可以处理X、Y、Z方向以及它们的组合。与2D版本相比,3D版本增加了方向类型参数,允许用户指定测量的方向性。该类还实现了AM装置的测量序列生成,支持单孔和双孔的AM测量模式。
#### 类图
```mermaid
classDiagram
class CCrossHoleConfig3DMainDlg {
+static GetInstance()
+OnInitDialog()
+OnTcnSelchangeTabArChange()
+OnBnClickedBtnLoadGeometry()
+OnBnClickedBtnCreate()
+OnBnClickedBtnStartSimulation()
+OnBnClickedBtnStopSimulation()
+OnBnClickedBtnClose()
+OnDestroy()
+OnMsgCrossHoleMainWndBtn()
+ChangeTabPage()
#DoDataExchange()
#CalcLValue()
#TwoBoreholeGenerateScript()
#SaveTestPointToDB()
#OneBoreHoleGenerateScriptAM()
#TwoBoreHoleGenerateScriptAM()
#GetUniSptXPos()
-m_tabChange
-m_pConnection
-m_strScriptName
-m_strTimeInterval
-m_strOperator
-m_strNote
-m_uiEamount
-m_uiCHamount
-m_uiTPamount
-m_rcRect
-m_rcRectLoc
-m_strPoleDistance
-m_strPoleStep
-m_vecAllBoreholeABMNInfo
-m_iMediumType
-m_mapDatabaseABMNInfo
}
CCrossHoleConfig3DMainDlg --> CTabCtrl : "使用"
CCrossHoleConfig3DMainDlg --> _ConnectionPtr : "数据库连接"
CCrossHoleConfig3DMainDlg --> CDialog : "继承"
```
**图表来源**
- [CCrossHoleConfig3DMainDlg.h](file://h\crossHole\CCrossHoleConfig3DMainDlg.h#L14-L71)
- [CCrossHoleConfig3DMainDlg.cpp](file://cpp\crossHole\CCrossHoleConfig3DMainDlg.cpp#L1-L1300)
#### 3D测量序列生成流程
```mermaid
flowchart TD
A[开始] --> B{获取钻孔数量}
B --> |两个钻孔| C[调用TwoBoreholeGenerateScript]
B --> |一个钻孔| D[调用OneBoreHoleGenerateScriptAM]
C --> E[计算L值范围]
E --> F[遍历第一个钻孔的电极]
F --> G[遍历第二个钻孔的电极]
G --> H[计算AM、BM、AN、BN距离]
H --> I[计算K值]
I --> J[创建测量点记录]
J --> K{是否为多通道}
K --> |是| L[按A、B、M排序插入]
K --> |否| M[按顺序插入]
L --> N[保存到数据库]
M --> N
D --> O[遍历同一钻孔的电极对]
O --> P[计算AM距离]
P --> Q[计算K值]
Q --> R[创建AM测量点记录]
R --> S[保存到数据库]
N --> T[结束]
S --> T
```
**图表来源**
- [CCrossHoleConfig3DMainDlg.cpp](file://cpp\crossHole\CCrossHoleConfig3DMainDlg.cpp#L703-L800)
- [CCrossHoleConfig3DMainDlg.cpp](file://cpp\crossHole\CCrossHoleConfig3DMainDlg.cpp#L500-L701)
**章节来源**
- [CCrossHoleConfig3DMainDlg.cpp](file://cpp\crossHole\CCrossHoleConfig3DMainDlg.cpp#L1-L1300)
### MediumCrossHoleGeomative 分析
MediumCrossHoleGeomative类是跨孔测量的核心算法实现,继承自CMedium基类。该类负责实现特定于跨孔测量的K值计算公式和测量序列生成逻辑。K值计算采用几何平均法,考虑了电极间的实际距离和间隔系数。测量序列生成遵循特定的模式:以电极中点为基准,C1P1距离作为层数,逐层向下移动,同时C2P2从最高点逐次向下移动,每次移动两个电极间距,直到C1P1到达底部。
#### 类图
```mermaid
classDiagram
class CMediumCrossHoleGeomative {
+CMediumCrossHoleGeomative(int iAR)
+~CMediumCrossHoleGeomative()
+CalculateCESptKVal(float fA, float fB, float fX, float fY)
+GenerateSptRecElecVal(int iEAmount, int* pMaxLevel, int* pPtAmount, CPtrArray* pSptRecArray)
+CalculateSptPtLoc(int iMul, CSptRecord* pSptRecord)
+GenSptRecLevel(int iA, int iB, int iM, int iN)
+GenSptRecPosInLevel(int iA, int iB, int iM, int iN)
+GetMaxLevelByEAmount(int iEAmount)
-m_fSeprate
}
CMediumCrossHoleGeomative --> CMedium : "继承"
```
**图表来源**
- [MediumCrossHoleGeomative.h](file://h\MediumCrossHoleGeomative.h#L13)
- [MediumCrossHoleGeomative.cpp](file://cpp\ProblemZone\MediumCrossHoleGeomative.cpp#L1-L148)
#### 测量序列生成算法
```mermaid
flowchart TD
A[开始] --> B[初始化层数iLayer=0]
B --> C[层数加1]
C --> D[设置A位置为中点]
D --> E[计算M位置=A-层数]
E --> F{M位置<1?}
F --> |是| G[结束]
F --> |否| H[设置B位置为中点+1]
H --> I[计算N位置=B+层数]
I --> J{N位置>电极总数?}
J --> |是| K[移动A和M向下2个间距]
J --> |否| L[创建测量点记录]
L --> M[移动B和N向下2个间距]
M --> I
K --> N{A位置<2?}
N --> |是| G
N --> |否| H
G --> O[结束]
```
**图表来源**
- [MediumCrossHoleGeomative.cpp](file://cpp\ProblemZone\MediumCrossHoleGeomative.cpp#L47-L112)
**章节来源**
- [MediumCrossHoleGeomative.cpp](file://cpp\ProblemZone\MediumCrossHoleGeomative.cpp#L1-L148)
## 依赖分析
跨孔测量脚本系统具有清晰的依赖关系,主要依赖于数据库访问组件、几何计算工具和用户界面框架。核心依赖包括ADO数据库连接用于数据持久化,标准模板库(STL)用于数据结构管理,以及MFC框架用于用户界面实现。系统内部组件间通过明确的接口进行通信,如CCrossHoleConfig2DMainDlg和CCrossHoleConfig3DMainDlg通过GetInstance()方法提供单例访问,确保配置数据的一致性。MediumCrossHoleGeomative类与配置对话框之间通过标准数据结构(STBoreHolePoints、STDatabaseABMNInfo等)进行数据交换,降低了组件间的耦合度。
```mermaid
graph TD
A[CCrossHoleConfig2DMainDlg] --> B[数据库访问]
A --> C[STL容器]
A --> D[MFC框架]
A --> E[COption2DGeometryDlg]
A --> F[COption2DBoreholeDlg]
A --> G[COption2DSurfaceDlg]
A --> H[COption2DSettingDlg]
A --> I[CCrosshole2dDrawingBoardDlg]
J[CCrossHoleConfig3DMainDlg] --> B
J --> C
J --> D
J --> K[COption3DGeometryDlg]
J --> L[COption3DBoreholeDlg]
J --> M[COption3DSurfaceDlg]
J --> N[COption3DSettingDlg]
J --> O[CCrosshole3dDrawingBoardDlg]
P[MediumCrossHoleGeomative] --> B
P --> C
P --> Q[CMedium基类]
A --> P
J --> P
```
**图表来源**
- [CCrossHoleConfig2DMainDlg.h](file://h\crossHole\CCrossHoleConfig2DMainDlg.h#L14-L64)
- [CCrossHoleConfig3DMainDlg.h](file://h\crossHole\CCrossHoleConfig3DMainDlg.h#L14-L71)
- [MediumCrossHoleGeomative.h](file://h\MediumCrossHoleGeomative.h#L13)
**章节来源**
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp\crossHole\CCrossHoleConfig2DMainDlg.cpp#L1-L912)
- [CCrossHoleConfig3DMainDlg.cpp](file://cpp\crossHole\CCrossHoleConfig3DMainDlg.cpp#L1-L1300)
- [MediumCrossHoleGeomative.cpp](file://cpp\ProblemZone\MediumCrossHoleGeomative.cpp#L1-L148)
## 性能考虑
跨孔测量脚本的性能主要受测量点数量和数据库操作效率的影响。系统采用批量数据库插入操作,减少了与数据库的交互次数,提高了数据保存效率。在测量序列生成过程中,算法的时间复杂度为O(n²),其中n为电极数量,对于大规模电极阵列可能成为性能瓶颈。建议在实际应用中合理控制电极数量和测量密度,避免生成过多的测量点。此外,系统使用内存中的数据结构暂存测量点信息,然后再一次性写入数据库,这种设计平衡了内存使用和I/O性能。
## 故障排除指南
在使用跨孔测量脚本时,可能会遇到以下常见问题:
1. **脚本创建失败**:检查脚本名称是否为空,确保输入了有效的脚本名称。
2. **电极坐标加载失败**:确认Geomative文件格式正确,坐标数据以逗号分隔。
3. **K值计算异常**:检查AM距离和间隔系数是否为零,这些值不能为零。
4. **数据库保存失败**:确保数据库连接正常,检查是否有重复的脚本名称。
5. **测量点数量异常**:验证钻孔电极数量是否符合要求,确保有足够的电极进行测量。
**章节来源**
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp\crossHole\CCrossHoleConfig2DMainDlg.cpp#L755-L763)
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp\crossHole\CCrossHoleConfig2DMainDlg.cpp#L564-L577)
- [MediumCrossHoleGeomative.cpp](file://cpp\ProblemZone\MediumCrossHoleGeomative.cpp#L30-L43)
## 结论
跨孔测量脚本系统提供了一套完整的解决方案,用于生成和管理跨孔电法测量的配置。通过CCrossHoleConfig2DMainDlg和CCrossHoleConfig3DMainDlg对话框,用户可以方便地配置钻孔位置、电极间距和测量模式。MediumCrossHoleGeomative类实现了核心的测量序列生成算法,确保了测量数据的科学性和有效性。系统采用模块化设计,具有良好的可扩展性和可维护性。在水文地质调查中,该系统能够有效支持地下介质的精细探测,为工程决策提供可靠的数据支持。未来可以进一步优化算法性能,增加更多的测量模式支持,提升用户体验。
@@ -0,0 +1,378 @@
# 固件升级
<cite>
**本文档引用的文件**
- [LicenseUpgrade.cpp](file://cpp/Operator/LicenseUpgrade.cpp)
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp)
- [GD10OperCmd.h](file://h/GD10OperCmd.h)
- [FileTransfer.cpp](file://cpp/Tools/FileTransfer.cpp)
- [FileTransfer.h](file://h/FileTransfer.h)
- [IAP-GD10.bat](file://tools/IAP-GD10.bat)
- [License-GD10.bat](file://tools/License-GD10.bat)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp)
</cite>
## 目录
1. [引言](#引言)
2. [固件升级流程概述](#固件升级流程概述)
3. [核心组件分析](#核心组件分析)
4. [升级准备阶段](#升级准备阶段)
5. [文件传输机制](#文件传输机制)
6. [升级执行与DFU工具](#升级执行与dfu工具)
7. [通信协议与指令集](#通信协议与指令集)
8. [升级状态监控与用户反馈](#升级状态监控与用户反馈)
9. [异常处理与恢复机制](#异常处理与恢复机制)
10. [版本兼容性考虑](#版本兼容性考虑)
## 引言
本文档全面描述了通过LicenseUpgrade模块触发并执行GD10设备固件升级的完整流程。文档详细阐述了升级准备、文件传输、升级执行、校验与重启等各个阶段的技术细节。通过分析GD10OperCmd中定义的升级指令集及其通信协议,解释了批处理脚本在调用DFU工具和传递参数中的作用。同时提供了升级失败、中断恢复、版本兼容性等关键问题的处理指南,并结合实际代码逻辑展示了升级状态监控和用户反馈机制。
## 固件升级流程概述
GD10设备的固件升级流程是一个多阶段的复杂过程,涉及多个组件的协同工作。整个流程从用户通过LicenseUpgrade模块触发升级开始,经过升级准备、文件下载、设备通信、固件刷写和最终验证等阶段。该流程依赖于FileTransfer组件进行文件传输,利用批处理脚本调用DFU工具执行实际的固件刷写操作,并通过GD10OperCmd定义的通信协议与设备进行交互。
```mermaid
flowchart TD
A[用户触发升级] --> B[升级准备]
B --> C[下载升级文件]
C --> D[建立设备通信]
D --> E[执行固件刷写]
E --> F[校验与重启]
F --> G[升级完成]
```
**图示来源**
- [LicenseUpgrade.cpp](file://cpp/Operator/LicenseUpgrade.cpp#L146-L269)
- [IAP-GD10.bat](file://tools/IAP-GD10.bat#L12-L16)
## 核心组件分析
### LicenseUpgrade模块
LicenseUpgrade模块是固件升级流程的入口点,负责协调整个升级过程。该模块通过对话框界面与用户交互,收集必要的升级信息,并协调其他组件完成升级任务。
```mermaid
classDiagram
class CLicenseUpgrade {
+m_bIsCrulInitaled bool
+m_bIsUpdating bool
+m_comDev CComboBox
+m_proDownFile CProgressCtrl
+m_FileTransfer FileTransfer
+OnInitDialog() BOOL
+OnOK() void
+GetLicenseFile(strDev CString) bool
+OnTimer(nIDEvent UINT) void
+UpdateGD10Dev(pCom CSComPort*) void
}
CLicenseUpgrade --> FileTransfer : "使用"
CLicenseUpgrade --> CSComPort : "通信"
```
**图示来源**
- [LicenseUpgrade.cpp](file://cpp/Operator/LicenseUpgrade.cpp#L20-L496)
- [FileTransfer.h](file://h/FileTransfer.h#L26-L46)
### GD10OperCmd指令集
GD10OperCmd类定义了与GD10设备通信的指令集,是实现设备控制的核心组件。该组件提供了项目管理、测区管理、脚本管理等功能的接口。
```mermaid
classDiagram
class CGD10OperCmd {
+m_pGD10Oper CGD10OperCmd*
+GetInstance() CGD10OperCmd*
+project_add(mac char*, projectcn char*) int
+project_delete(mac char*, projectcn char*) bool
+testzone_add(projectcn char*, testzonecn char*, type char*) int
+testzone_delete(projectcn char*, testzonecn char*) int
+script_add(scriptcn char*, scriptname char*, mudiumid char*) int
+script_delete(scriptcn char*) bool
+set_param(strParam CString) bool
+unregister_user(strMacAddr CString) bool
+loadDeviceMarkDataFromGD() bool
+LoadDevMarkDataFormGDThread(lParam LPVOID) UINT
}
CGD10OperCmd : "单例模式"
```
**图示来源**
- [GD10OperCmd.h](file://h/GD10OperCmd.h#L12-L52)
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp#L24-L800)
## 升级准备阶段
升级准备阶段是固件升级流程的初始阶段,主要负责验证升级条件、初始化必要组件和设置升级参数。此阶段确保所有前置条件满足后,才开始实际的文件传输和固件刷写操作。
```mermaid
flowchart TD
A[初始化对话框] --> B[检查设备连接]
B --> C{设备是否在线?}
C --> |否| D[显示错误信息]
C --> |是| E[获取在线设备列表]
E --> F[设置进度条范围]
F --> G[初始化文件传输组件]
G --> H[准备升级]
```
**图示来源**
- [LicenseUpgrade.cpp](file://cpp/Operator/LicenseUpgrade.cpp#L49-L97)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L56-L78)
**本节来源**
- [LicenseUpgrade.cpp](file://cpp/Operator/LicenseUpgrade.cpp#L49-L97)
## 文件传输机制
文件传输机制是固件升级流程中的关键环节,负责从远程服务器下载必要的升级文件到本地。该机制使用FileTransfer组件实现,支持进度监控和错误处理。
### FileTransfer组件
FileTransfer组件是基于C++的文件传输实现,提供了文件发送和接收的基本功能。该组件使用串口通信(CSComPort)作为传输媒介,并支持CRC校验确保数据完整性。
```mermaid
classDiagram
class FileTransfer {
+port CSComPort*
+file FILE*
+file_length long
+byte_count long
+file_count int
+file_name[128] char
+buffer[BUFFSIZE] char
+Send(files char*[]) BOOL
+Receive(Path CString) BOOL
+error(fmt char*, ...) void
+status(fmt char*, ...) void
}
FileTransfer --> CSComPort : "使用"
FileTransfer : "抽象基类"
```
**图示来源**
- [FileTransfer.h](file://h/FileTransfer.h#L26-L46)
- [FileTransfer.cpp](file://cpp/Tools/FileTransfer.cpp#L28-L47)
### 文件下载流程
文件下载流程从远程服务器获取固件升级所需的文件,包括FACTORY和LICENSE文件。该流程支持进度显示和错误恢复。
```mermaid
sequenceDiagram
participant UI as "用户界面"
participant LU as "LicenseUpgrade"
participant FT as "FileTransfer"
participant Server as "远程服务器"
UI->>LU : 点击升级按钮
LU->>LU : 验证设备选择
LU->>FT : 初始化传输组件
LU->>FT : 设置下载参数
loop 下载每个文件
LU->>FT : 开始下载
FT->>Server : 发送HTTP请求
Server-->>FT : 返回文件数据
FT->>LU : 更新下载进度
LU->>UI : 显示进度
end
FT-->>LU : 下载完成
LU->>LU : 准备固件刷写
```
**图示来源**
- [LicenseUpgrade.cpp](file://cpp/Operator/LicenseUpgrade.cpp#L215-L269)
- [FileTransfer.h](file://h/FileTransfer.h#L40-L41)
**本节来源**
- [LicenseUpgrade.cpp](file://cpp/Operator/LicenseUpgrade.cpp#L173-L269)
- [FileTransfer.h](file://h/FileTransfer.h#L26-L46)
## 升级执行与DFU工具
升级执行阶段使用DFUDevice Firmware Upgrade)工具将下载的固件文件刷写到GD10设备中。这一过程通过批处理脚本调用DFU工具完成,确保了升级过程的可靠性和一致性。
### IAP-GD10批处理脚本
IAP-GD10.bat批处理脚本是执行固件升级的核心脚本,它调用DFU工具完成固件刷写。该脚本首先使用DfuCreateFile工具将二进制固件文件转换为DFU格式,然后使用DfuSeCommand工具将DFU文件刷写到设备中。
```mermaid
flowchart TD
A[开始] --> B[延迟10秒]
B --> C[创建DFU文件]
C --> D[刷写固件]
D --> E[删除临时DFU文件]
E --> F[结束]
```
**图示来源**
- [IAP-GD10.bat](file://tools/IAP-GD10.bat#L10-L16)
### License-GD10批处理脚本
License-GD10.bat批处理脚本专门用于升级设备的许可证文件。该脚本分两步执行:首先刷写FACTORY文件,然后刷写LICENSE文件,确保许可证信息正确更新。
```mermaid
flowchart TD
A[开始] --> B[延迟2秒]
B --> C[创建FACTORY DFU文件]
C --> D[刷写FACTORY文件]
D --> E[删除FACTORY DFU文件]
E --> F[创建LICENSE DFU文件]
F --> G[刷写LICENSE文件]
G --> H[删除LICENSE DFU文件]
H --> I[结束]
```
**图示来源**
- [License-GD10.bat](file://tools/License-GD10.bat#L7-L20)
### DFU工具参数说明
DFU工具的调用参数具有特定含义,确保固件正确刷写到设备的指定位置:
- `0x0483`: STMicroelectronics的厂商ID
- `0xdf11`: DFU设备的产品ID
- `0x2200`: 设备的设备ID
- `APP`: 固件类型标识
- `0x08010000`: 固件在设备内存中的起始地址
- `"APP.dfu"`: 生成的DFU文件名
这些参数确保了固件被正确识别和刷写到GD10设备中。
**本节来源**
- [IAP-GD10.bat](file://tools/IAP-GD10.bat#L12-L16)
- [License-GD10.bat](file://tools/License-GD10.bat#L9-L20)
## 通信协议与指令集
GD10设备的通信协议定义了一套完整的指令集,用于控制设备的各种操作。这些指令通过串口通信发送到设备,实现对设备的远程控制。
### 指令集功能
GD10OperCmd类定义的指令集涵盖了设备管理的各个方面:
- **项目管理**: `project_add``project_delete`用于在设备上创建和删除项目
- **测区管理**: `testzone_add``testzone_delete`用于管理测区
- **脚本管理**: `script_add``script_delete`用于管理测量脚本
- **参数设置**: `set_param`用于设置设备参数
- **用户管理**: `unregister_user`用于用户注销
### 通信流程
通信流程遵循典型的请求-响应模式,确保指令的可靠执行:
```mermaid
sequenceDiagram
participant App as "应用程序"
participant Cmd as "GD10OperCmd"
participant Dev as "GD10设备"
App->>Cmd : 调用指令方法
Cmd->>Cmd : 验证设备连接
Cmd->>Dev : 发送指令
Dev-->>Cmd : 返回响应
Cmd->>App : 返回执行结果
alt 执行成功
App->>App : 更新UI状态
else 执行失败
App->>App : 显示错误信息
end
```
**图示来源**
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp#L53-L800)
- [GD10OperCmd.h](file://h/GD10OperCmd.h#L20-L37)
**本节来源**
- [GD10OperCmd.h](file://h/GD10OperCmd.h#L20-L37)
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp#L53-L800)
## 升级状态监控与用户反馈
升级过程中的状态监控和用户反馈机制确保用户能够实时了解升级进度,并在出现问题时及时获得提示。
### 进度监控实现
进度监控通过定时器和文件传输组件的回调机制实现,实时更新用户界面:
```mermaid
flowchart TD
A[启动定时器] --> B[获取当前下载大小]
B --> C[获取文件总大小]
C --> D[计算进度百分比]
D --> E[更新进度条]
E --> F[更新进度文本]
F --> G{升级完成?}
G --> |否| H[继续监控]
G --> |是| I[停止定时器]
```
**图示来源**
- [LicenseUpgrade.cpp](file://cpp/Operator/LicenseUpgrade.cpp#L293-L324)
### 用户反馈机制
用户反馈机制通过消息框和界面元素更新提供清晰的状态信息:
- **成功反馈**: 显示"升级成功"消息框
- **失败反馈**: 显示具体的错误信息
- **进度反馈**: 实时更新进度条和百分比文本
- **警告反馈**: 提示电量不足等潜在问题
```mermaid
flowchart TD
A[升级开始] --> B[显示"正在升级"状态]
B --> C[监控升级过程]
C --> D{升级成功?}
D --> |是| E[显示"升级成功"消息]
D --> |否| F[显示错误详情]
E --> G[关闭对话框]
F --> H[保持对话框]
```
**本节来源**
- [LicenseUpgrade.cpp](file://cpp/Operator/LicenseUpgrade.cpp#L100-L171)
- [LicenseUpgrade.cpp](file://cpp/Operator/LicenseUpgrade.cpp#L293-L324)
## 异常处理与恢复机制
异常处理与恢复机制确保升级过程在遇到问题时能够安全终止,并尽可能恢复到稳定状态。
### 常见异常情况
升级过程中可能遇到的异常情况包括:
- **设备连接中断**: 设备在升级过程中断开连接
- **文件下载失败**: 无法从服务器下载升级文件
- **电量不足**: 设备电量过低,无法安全执行升级
- **超时错误**: 操作在规定时间内未完成
- **权限不足**: 缺少执行升级所需的权限
### 异常处理策略
针对不同异常情况,系统采用相应的处理策略:
```mermaid
flowchart TD
A[检测到异常] --> B{异常类型}
B --> |文件下载失败| C[删除已下载的临时文件]
B --> |电量不足| D[终止升级并提示充电]
B --> |超时错误| E[释放资源并关闭连接]
B --> |权限不足| F[提示用户检查权限]
C --> G[清理资源]
D --> G
E --> G
F --> G
G --> H[显示错误信息]
```
**图示来源**
- [LicenseUpgrade.cpp](file://cpp/Operator/LicenseUpgrade.cpp#L247-L262)
- [LicenseUpgrade.cpp](file://cpp/Operator/LicenseUpgrade.cpp#L363-L370)
**本节来源**
- [LicenseUpgrade.cpp](file://cpp/Operator/LicenseUpgrade.cpp#L247-L262)
- [LicenseUpgrade.cpp](file://cpp/Operator/LicenseUpgrade.cpp#L363-L370)
## 版本兼容性考虑
版本兼容性是固件升级过程中需要重点考虑的问题,确保新固件与现有硬件和软件环境的兼容性。
### 兼容性检查
在执行升级前,系统应进行以下兼容性检查:
- **硬件版本检查**: 确认固件与设备硬件版本匹配
- **软件版本检查**: 确保升级不会破坏现有功能
- **依赖项检查**: 验证所有依赖组件的版本兼容性
- **配置兼容性**: 确保新固件支持现有配置
### 回滚机制
为应对升级后可能出现的兼容性问题,应具备回滚机制:
- **备份旧固件**: 在升级前备份当前固件
- **快速恢复**: 提供快速恢复到旧版本的功能
- **配置保留**: 确保用户配置在回滚后仍然有效
- **日志记录**: 记录升级和回滚过程,便于问题排查
虽然当前代码中未显式实现回滚机制,但通过分阶段的升级流程和临时文件管理,为实现回滚提供了基础。
**本节来源**
- [LicenseUpgrade.cpp](file://cpp/Operator/LicenseUpgrade.cpp#L156-L157)
- [LicenseUpgrade.cpp](file://cpp/Operator/LicenseUpgrade.cpp#L443-L495)
@@ -0,0 +1,165 @@
# 设备状态管理
<cite>
**本文档引用的文件**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
- [DevManager.h](file://h/DevManager.h)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp)
- [Device.h](file://h/Device.h)
- [StateProcessor.cpp](file://cpp/Tools/StateProcessor.cpp)
- [StateProcessor.h](file://h/StateProcessor.h)
- [DialDevStatusTimerShow.cpp](file://cpp/Views/DialDevStatusTimerShow.cpp)
- [DialDevStatusTimerShow.h](file://h/DialDevStatusTimerShow.h)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h)
- [Constant.h](file://h/Constant.h)
</cite>
## 目录
1. [系统概述](#系统概述)
2. [CDevManager状态监控机制](#cdevmanager状态监控机制)
3. [CDevice状态字段设计与更新逻辑](#cdevice状态字段设计与更新逻辑)
4. [状态处理器(StateProcessor)作用](#状态处理器stateprocessor作用)
5. [DialDevStatusTimerShow状态可视化](#dialdevstatustimershows状态可视化)
6. [状态同步异常诊断与恢复](#状态同步异常诊断与恢复)
## 系统概述
GeomativeStudio系统通过CDevManager、CDevice、StateProcessor等核心组件实现对设备运行状态的全面监控与管理。系统采用定时轮询和事件驱动相结合的机制,实时监控设备的在线、离线、忙、空闲等状态。CDevManager作为设备管理的核心类,负责设备的生命周期管理和状态维护;CDevice类封装了单个设备的状态信息和行为;StateProcessor负责状态与UI显示之间的转换;DialDevStatusTimerShow对话框则提供了状态的可视化展示界面。整个系统通过心跳包、状态码解析和回调通知等机制,确保设备状态的准确同步和及时更新。
## CDevManager状态监控机制
CDevManager类通过定时轮询和事件驱动两种机制监控设备状态。在初始化时,通过InitialDevLinkList方法从数据库加载所有设备并设置初始状态为离线(PZ_STATE_OFFLINE)。系统通过GetOLDevList和GetFLDevList方法分别获取在线和离线设备列表,其中在线设备包括状态为PZ_STATE_ONLINE和PZ_STATE_NEW的设备。当设备连接或断开时,通过事件驱动机制更新设备状态:当设备上线时,调用AddRemoteDevice将设备信息加入远程设备集合,并更新设备状态为在线;当设备下线时,调用DeleteRemoteDevice从集合中移除设备,并将状态更新为离线。CDevManager还通过UpdateDevInfo方法接收设备同步参数,更新设备的硬件版本、软件版本、电池电压等信息,并持久化到数据库中。
**Section sources**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L160-L201)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L485-L591)
- [DevManager.h](file://h/DevManager.h#L16-L66)
## CDevice状态字段设计与更新逻辑
CDevice类中的状态字段m_uState是设备状态管理的核心,其设计基于Constant.h中定义的状态常量。设备状态包括PZ_STATE_OFFLINE(离线)、PZ_STATE_ONLINE(在线)和PZ_STATE_NEW(新设备)等。在构造函数中,设备初始状态被设置为PZ_STATE_OFFLINE。状态更新主要通过SetState方法实现,该方法被多个组件调用以反映设备的当前状态。例如,当设备成功连接时,ExecOperator等组件会将状态更新为PZ_STATE_ONLINE;当设备断开连接时,状态被重置为PZ_STATE_OFFLINE。对于新注册的设备,状态被设置为PZ_STATE_NEW,表示设备已注册但尚未建立连接。状态变化时,系统会触发相应的回调通知,更新UI显示和数据库记录。
```mermaid
classDiagram
class CDevice {
+DWORD m_dwID
+UINT m_uState
+UINT m_uType
+BYTE m_ucDevType
+CString m_szDevSN
+CString m_szDevName
+CString m_szModelNO
+CString m_szMDate
+CString m_szHWV
+CString m_szSWV
+CString m_szMBatch
+CString m_szMacAddress
+CSComPort m_sComPort
+_ConnectionPtr m_pConnection
+FILE* m_pLogFile
+SetState(UINT uState)
+SetID(DWORD dwID)
+PrintLog(CString& strLog)
}
class CDevManager {
+CLinkList<CDevice*> m_devLinkList
+_ConnectionPtr m_pConnection
+std : : set<STSigRemoteDev> m_setRemoteDev
+CHandleProcessor m_handleProcessor
+GetDeviceByID(DWORD dwDevID)
+GetDevice(DWORD dwHandle)
+GetDevice(CString szDevSN)
+InitialDevLinkList()
+AddDevice(CDevice* const pDev)
+DeleteObjInMem(DWORD dwHandle)
+DeleteObjInMem(CString szDevSN)
+AddObjInMem(CString szDevSN)
+AddOfflineObjInMem(CString szDevSN)
+DeleteDevice(DWORD dwHandle)
+GetOLDevList(CPtrArray* pOLDevList)
+GetFLDevList(CPtrArray* pFLDevList)
+UpdateDevInfo(STSynDevParam stDevParam, BYTE bRemoteDeveTyp)
+SetDeviceHandle(CDevice* const pDev)
+GetRegisterDevice(CString szDevSN, bool& bIsRegister)
+DeleteDevice(CString strDev)
+AddRemoteDevice(STSigRemoteDev stDevice)
+DeleteRemoteDevice(STSigRemoteDev stDevice)
+GetRemoteDeviceInfo()
}
CDevManager --> CDevice : "管理"
CDevice --> CDevManager : "状态更新"
```
**Diagram sources**
- [Device.h](file://h/Device.h#L33-L127)
- [DevManager.h](file://h/DevManager.h#L16-L66)
**Section sources**
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L43-L73)
- [Device.h](file://h/Device.h#L88-L105)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L191-L192)
## 状态处理器(StateProcessor)作用
StateProcessor类在设备状态管理和UI显示之间起着桥梁作用。其主要功能是实现设备状态与UI图像状态之间的相互转换。通过ChangeToImageState方法,将设备的内部状态值(如PZ_STATE_ONLINE、PZ_STATE_OFFLINE)转换为TreeView控件使用的图像状态掩码,从而在UI上显示对应的状态图标。反之,通过ChangeToItemState方法,将UI的图像状态转换回内部状态值,便于程序逻辑处理。这种转换机制使得UI显示与业务逻辑分离,提高了代码的可维护性和可扩展性。StateProcessor的实现简单高效,仅包含两个核心方法,避免了复杂的依赖关系。
```mermaid
flowchart TD
A["设备状态更新 (PZ_STATE_ONLINE)"] --> B["StateProcessor::ChangeToImageState()"]
B --> C["生成图像状态掩码"]
C --> D["TreeView控件显示在线图标"]
D --> E["用户看到设备在线"]
F["用户选择设备项"] --> G["TreeView获取图像状态"]
G --> H["StateProcessor::ChangeToItemState()"]
H --> I["转换为内部状态值"]
I --> J["程序逻辑处理"]
```
**Diagram sources**
- [StateProcessor.cpp](file://cpp/Tools/StateProcessor.cpp#L19-L40)
- [StateProcessor.h](file://h/StateProcessor.h#L12-L22)
**Section sources**
- [StateProcessor.cpp](file://cpp/Tools/StateProcessor.cpp#L19-L40)
- [StateProcessor.h](file://h/StateProcessor.h#L14-L19)
## DialDevStatusTimerShow状态可视化
DialDevStatusTimerShow对话框实现了设备状态的可视化展示,特别是PLC设备的状态信息。该对话框继承自CDialog,包含一个CListCtrl控件(m_listData)用于显示状态数据。在OnInitDialog方法中,初始化列表控件的列标题,包括时间、电压、温度和开关状态等。ShowPlcStatusData方法从TaskDataOper组件查询PLC状态数据,并将数据填充到列表控件中。数据显示包括模拟量电压(Voltage1-4)、电池电压、温度和四个开关的开关状态(ON/OFF)。通过设置列表控件的扩展样式(如LVS_EX_FULLROWSELECT、LVS_EX_GRIDLINES),提升了用户体验。该对话框为用户提供了直观的设备状态历史视图,便于监控设备运行状况。
```mermaid
sequenceDiagram
participant Dialog as "DialDevStatusTimerShow"
participant DataOper as "TaskDataOper"
participant DB as "数据库"
Dialog->>Dialog : OnInitDialog()
Dialog->>Dialog : 初始化列表控件列
Dialog->>Dialog : 设置扩展样式
Dialog->>DataOper : QueryPlcStatusData()
DataOper->>DB : 查询PLC状态数据
DB-->>DataOper : 返回状态数据
DataOper-->>Dialog : 返回状态数据向量
loop 遍历每个状态数据
Dialog->>Dialog : 格式化时间字符串
Dialog->>Dialog : 插入列表项
loop 显示6个模拟量
Dialog->>Dialog : 格式化电压值
Dialog->>Dialog : 设置单元格文本
end
loop 显示4个开关状态
Dialog->>Dialog : 转换开关值为ON/OFF
Dialog->>Dialog : 设置单元格文本
end
end
```
**Diagram sources**
- [DialDevStatusTimerShow.cpp](file://cpp/Views/DialDevStatusTimerShow.cpp#L45-L144)
- [DialDevStatusTimerShow.h](file://h/DialDevStatusTimerShow.h#L13-L44)
**Section sources**
- [DialDevStatusTimerShow.cpp](file://cpp/Views/DialDevStatusTimerShow.cpp#L45-L144)
- [DialDevStatusTimerShow.h](file://h/DialDevStatusTimerShow.h#L13-L44)
## 状态同步异常诊断与恢复
系统针对状态同步异常、心跳丢失和状态不一致等问题提供了完善的诊断与恢复策略。当设备长时间未收到心跳包(EN_REQ_HEART_BEAT_PACKET)时,系统判定为心跳丢失,将设备状态从PZ_STATE_ONLINE更新为PZ_STATE_OFFLINE,并记录日志。对于状态不一致问题,系统通过定时轮询和事件驱动双重机制确保状态同步:定时轮询定期检查设备连接状态,而事件驱动机制在收到设备上线/下线通知(EN_RECV_NOTIFY_DEVICE_ONLINE/OFFLINE)时立即更新状态。诊断策略包括:检查网络连接、验证设备响应、比对数据库记录与内存状态。恢复策略包括:重新建立连接、强制状态同步、重启设备通信模块。系统还通过UpdateDevInfo方法确保设备参数的及时更新,避免因参数不一致导致的状态错误。
**Section sources**
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L546-L547)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L592-L642)
- [DevManager.h](file://h/DevManager.h#L43-L60)
@@ -0,0 +1,393 @@
# 设备管理
<cite>
**本文引用的文件**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
- [DevManager.h](file://h/DevManager.h)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp)
- [Device.h](file://h/Device.h)
- [HandleProcessor.cpp](file://cpp/Tools/HandleProcessor.cpp)
- [HandleProcessor.h](file://h/HandleProcessor.h)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h)
- [Constant.h](file://h/Constant.h)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [组件详解](#组件详解)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件系统性文档化设备管理模块的实现细节,重点覆盖:
- CDevManager 类如何管理设备生命周期(连接、状态监控、固件升级、删除)
- 设备链表 m_devLinkList 的数据结构设计与句柄处理器 HandleProcessor 的集成机制
- CDevice 类的数据模型与其与数据库的交互方式
- 设备注册、状态变更与异常处理的实际调用路径
- 与项目管理器、脚本管理器等模块的协作关系
- 在线/离线模式下的行为差异
- 设备通信协议、错误码处理与性能优化建议
## 项目结构
设备管理相关代码主要分布在以下目录与文件:
- 管理层:DevManager(设备管理器)、ProManager(项目管理器)、SptManager(脚本管理器)
- 业务层:Device(设备实体)
- 工具层:HandleProcessor(句柄处理器)、CtrlProtocolDef(通信协议与错误码定义)
- 视图层:devmngframe(设备管理界面框架),用于触发升级、参数修改等操作
- 工具:checkupdate(固件升级工具)
```mermaid
graph TB
subgraph "管理层"
DM["CDevManager<br/>设备管理器"]
PM["CProManager<br/>项目管理器"]
SM["CSptManager<br/>脚本管理器"]
end
subgraph "业务层"
DEV["CDevice<br/>设备实体"]
end
subgraph "工具层"
HP["CHandleProcessor<br/>句柄处理器"]
CPD["CtrlProtocolDef<br/>通信协议/错误码"]
CT["Constant<br/>常量/状态/句柄位宽"]
end
subgraph "视图层"
DVF["CDevMngFrame<br/>设备管理界面"]
CU["Ccheckupdate<br/>固件升级工具"]
end
DM --> DEV
DM --> HP
DM --> CPD
DM --> CT
PM --> DM
SM --> DM
DVF --> DM
DVF --> DEV
DVF --> CU
```
图表来源
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L1-L200)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L1-L120)
- [HandleProcessor.cpp](file://cpp/Tools/HandleProcessor.cpp#L1-L96)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L1-L120)
- [Constant.h](file://h/Constant.h#L60-L120)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L1-L120)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L1780-L1840)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L47-L96)
- [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp#L1292-L1336)
章节来源
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L1-L200)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L1-L120)
- [HandleProcessor.cpp](file://cpp/Tools/HandleProcessor.cpp#L1-L96)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L1-L120)
- [Constant.h](file://h/Constant.h#L60-L120)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L1-L120)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L1780-L1840)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L47-L96)
- [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp#L1292-L1336)
## 核心组件
- CDevManager:负责设备生命周期管理、设备链表维护、句柄分配、数据库交互、在线/离线设备列表构建、远程设备集合维护、设备信息更新等。
- CDevice:封装设备数据模型(ID、状态、类型、序列号、硬件/软件版本、电池电压、参数等),并提供与数据库交互的方法(展示详情、读取/写入参数、文件收发、GR/AC信息等)。
- CHandleProcessor:负责句柄生成与解析,将ID与类型打包进统一的DWORD句柄,支持从句柄中提取ID与类型。
- CtrlProtocolDef:定义控制协议头、设备参数结构、命令字、错误码、远程设备信息等。
- Constant:定义句柄位宽、状态枚举、消息常量、缓冲区大小、轮询超时等通用常量。
章节来源
- [DevManager.h](file://h/DevManager.h#L1-L69)
- [Device.h](file://h/Device.h#L1-L128)
- [HandleProcessor.h](file://h/HandleProcessor.h#L1-L29)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L1-L120)
- [Constant.h](file://h/Constant.h#L60-L120)
## 架构总览
设备管理模块围绕“设备管理器-设备实体-句柄处理器-通信协议-视图/工具”的分层组织,形成清晰的职责边界与调用链路。
```mermaid
sequenceDiagram
participant UI as "视图/界面"
participant DM as "CDevManager"
participant DEV as "CDevice"
participant HP as "CHandleProcessor"
participant DB as "数据库"
participant NET as "网络/远程设备"
UI->>DM : 请求初始化设备链表
DM->>DB : 查询设备表(device)
DB-->>DM : 返回设备记录集
loop 遍历记录
DM->>DEV : 构造CDevice实例
DM->>HP : 生成句柄(设备ID, 类型)
DM->>DM : m_devLinkList.Add(句柄, 设备)
end
UI->>DM : 获取在线/离线设备列表
DM->>DM : 遍历m_devLinkList
DM-->>UI : 返回在线/离线设备数组
UI->>DM : 更新设备参数/信息
DM->>DB : 写入设备参数/信息
DB-->>DM : 提交成功
UI->>DM : 删除设备
DM->>DB : 删除设备及关联表记录
DB-->>DM : 提交成功
UI->>DM : 远程设备上下线通知
DM->>NET : 维护远程设备集合(set)
DM-->>UI : 同步状态
```
图表来源
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L160-L201)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L486-L508)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L510-L591)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L592-L642)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L383-L433)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L435-L483)
- [DevManager.h](file://h/DevManager.h#L20-L66)
- [HandleProcessor.cpp](file://cpp/Tools/HandleProcessor.cpp#L29-L57)
## 组件详解
### CDevManager:设备生命周期与链表管理
- 初始化设备链表:从数据库读取设备记录,构造 CDevice 对象,生成句柄并加入 m_devLinkList。
- 设备查询:按ID、句柄、序列号查询设备,并进行MAC白名单匹配。
- 设备增删改:新增设备(含默认desetting/acds表初始化)、删除设备(级联清理)、设置句柄。
- 在线/离线列表:遍历链表筛选在线/离线设备。
- 远程设备集合:维护远程GD10/PLC设备集合,支持增删。
- 设备信息更新:接收远程设备参数,写入数据库。
```mermaid
flowchart TD
Start(["初始化设备链表"]) --> QueryDB["查询设备表(device)"]
QueryDB --> Loop{"遍历记录"}
Loop --> |是| NewDev["构造CDevice实例"]
NewDev --> GenHandle["生成句柄(设备ID, 类型)"]
GenHandle --> AddList["m_devLinkList.Add(句柄, 设备)"]
AddList --> Loop
Loop --> |否| End(["完成"])
subgraph "查询与筛选"
Q1["按ID查询"] --> Q2["按句柄查询"]
Q3["按序列号查询"] --> Q4["在线/离线列表"]
end
```
图表来源
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L160-L201)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L48-L80)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L82-L90)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L127-L158)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L486-L508)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L510-L591)
章节来源
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L48-L158)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L160-L201)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L203-L281)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L283-L294)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L296-L323)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L325-L381)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L383-L483)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L486-L591)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L592-L642)
- [DevManager.h](file://h/DevManager.h#L16-L66)
### CDevice:设备数据模型与数据库交互
- 数据模型:包含设备ID、状态、类型、序列号、名称、型号、硬件/软件版本、生产日期、批次、MAC地址、数据库连接指针等。
- 数据库交互:展示离线/在线详情、读取/写入desetting/acds参数、读取devgr/devac信息、执行脚本同步等。
- 文件传输:支持接收/发送文件(Zmodem流程),带重试逻辑。
- 参数与状态:提供参数修改、时间窗修改、锁机、重置等能力。
```mermaid
classDiagram
class CDevice {
+DWORD m_dwID
+UINT m_uState
+UINT m_uType
+BYTE m_ucDevType
+CString m_szDevSN
+CString m_szDevName
+CString m_szModelNO
+CString m_szHWV
+CString m_szSWV
+CString m_szMacAddress
+_ConnectionPtr m_pConnection
+PrintLog(strLog)
+ShowFLDetailInfo(list)
+ShowOLDetailInfo(list)
+ShowGRInfo(list)
+ShowACInfo(list)
+ReceiveFile(local, host, retry)
+SendFile(host, local, name)
}
```
图表来源
- [Device.h](file://h/Device.h#L33-L128)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L115-L192)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L193-L280)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L511-L547)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L549-L649)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L682-L727)
章节来源
- [Device.h](file://h/Device.h#L33-L128)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L115-L280)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L511-L649)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L682-L727)
### 句柄处理器 CHandleProcessorID与类型编码
- 生成句柄:将设备ID与类型按固定位宽打包,类型高位存放,ID低位存放。
- 解析句柄:从句柄中提取ID与类型。
- 位宽定义:来自 Constant 中 HANDLE_OFFSET 常量,确保ID与类型的位域合理分配。
```mermaid
flowchart TD
A["输入: 设备ID, 类型"] --> B["类型左移HANDLE_OFFSET位"]
B --> C["ID按位或运算"]
C --> D["输出: 句柄DWORD"]
D --> E["解析: 取低27位ID, 取高5位类型"]
```
图表来源
- [HandleProcessor.cpp](file://cpp/Tools/HandleProcessor.cpp#L29-L57)
- [HandleProcessor.cpp](file://cpp/Tools/HandleProcessor.cpp#L59-L95)
- [Constant.h](file://h/Constant.h#L60-L70)
章节来源
- [HandleProcessor.cpp](file://cpp/Tools/HandleProcessor.cpp#L29-L95)
- [HandleProcessor.h](file://h/HandleProcessor.h#L12-L29)
- [Constant.h](file://h/Constant.h#L60-L70)
### 设备通信协议与错误码
- 协议头与参数结构:STCtrlProtoHeader、STSynDevParam、STModifyDevParam 等,定义了控制命令、数据类型、状态码、设备参数等。
- 命令字与状态:EN_CTRL_CMD_INFO 定义了登录、参数同步、参数设置、任务参数设置、测量数据、心跳等命令字;EN_RCV_MSG_RES/EN_ERROR_MSG 定义了接收结果与错误码。
- 远程设备信息:STSigRemoteDev 定义远程GD10/PLC设备标识与比较规则。
章节来源
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L46-L120)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L126-L237)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L441-L548)
### 设备注册、状态变更与异常处理
- 注册查询:GetRegisterDevice 会检查设备是否已在链表中存在,并与当前MAC白名单比对,避免跨网卡误判。
- 状态变更:CDevice::SetState 设置设备状态;CDevManager::UpdateDevInfo 将远程设备参数写入数据库。
- 异常处理:数据库事务 Begin/Commit/Rollback 包裹关键操作;捕获_com_error 并弹窗提示;全局钩子用于统一错误提示。
章节来源
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L92-L125)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L127-L158)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L592-L642)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L75-L84)
### 与项目管理器、脚本管理器的协作
- 项目管理器:通过句柄处理器解析工程/测试区句柄,构建数据管理结构(CProject/CTestingZone),并与设备建立关联(dptt表)。
- 脚本管理器:在离线模式下创建脚本文件,与设备ID关联;在线模式下通过设备与脚本同步(脚本下发/接收)。
章节来源
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L155-L182)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L184-L215)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L1782-L1834)
### 在线/离线模式行为差异
- 在线模式:设备状态可能为 EN_DEV_ONLINE 或 NEW;设备参数通过协议同步至数据库;支持实时数据接收与状态通知。
- 离线模式:设备状态为 OFFLINE;通过数据库直接展示设备参数与历史数据;部分操作(如参数同步)受限。
章节来源
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L42-L44)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L486-L508)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L1710-L1753)
### 固件升级与参数修改
- 固件升级:通过 CDevMngFrame 触发升级流程,使用 Ccheckupdate 下载/校验/执行升级,涉及文件发送、命令下发与结果校验。
- 参数修改:通过 CDevice 接口修改参数,结合 CtrlProtocolDef 中的命令字与参数结构进行下发与确认。
章节来源
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L47-L96)
- [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp#L1292-L1336)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L508-L548)
## 依赖关系分析
- CDevManager 依赖 CDevice、CHandleProcessor、CtrlProtocolDef、Constant、数据库连接。
- CDevice 依赖数据库连接、文件传输工具、对话框组件。
- 视图层(CDevMngFrame)依赖设备管理器与升级工具。
- 项目/脚本管理器通过句柄与设备管理器解耦协作。
```mermaid
graph LR
DM["CDevManager"] --> DEV["CDevice"]
DM --> HP["CHandleProcessor"]
DM --> CPD["CtrlProtocolDef"]
DM --> CT["Constant"]
DEV --> DB["数据库"]
DVF["CDevMngFrame"] --> DM
DVF --> CU["Ccheckupdate"]
PM["CProManager"] --> DM
SM["CSptManager"] --> DM
```
图表来源
- [DevManager.h](file://h/DevManager.h#L16-L66)
- [Device.h](file://h/Device.h#L33-L128)
- [HandleProcessor.h](file://h/HandleProcessor.h#L12-L29)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L1-L120)
- [Constant.h](file://h/Constant.h#L60-L120)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L155-L182)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L1782-L1834)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L47-L96)
- [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp#L1292-L1336)
章节来源
- [DevManager.h](file://h/DevManager.h#L16-L66)
- [Device.h](file://h/Device.h#L33-L128)
- [HandleProcessor.h](file://h/HandleProcessor.h#L12-L29)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L1-L120)
- [Constant.h](file://h/Constant.h#L60-L120)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L155-L182)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp#L1782-L1834)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L47-L96)
- [checkupdate.cpp](file://cpp/Tools/checkupdate.cpp#L1292-L1336)
## 性能考量
- 句柄位宽与哈希/索引:HANDLE_OFFSET 与类型位域设计保证了O(1)的句柄解析与查找效率,适合大规模设备场景。
- 数据库事务:关键操作(新增/删除设备、参数更新)使用事务包裹,减少中间态风险,但需注意事务开销与锁竞争。
- 文件传输重试:接收文件具备重试机制,提升稳定性,但应限制最大重试次数与退避策略,避免阻塞UI。
- 轮询与超时:通信轮询次数与超时常量(MAX_POLLING_TIME、COMM_TIMEOUT)影响响应速度与资源占用,应根据实际通信环境调整。
- 在线/离线列表构建:遍历链表筛选在线/离线设备为O(N),建议在频繁刷新场景引入增量更新与缓存。
## 故障排查指南
- 设备注册失败:检查 GetRegisterDevice 中 MAC 白名单匹配逻辑,确认当前网卡MAC与设备记录一致。
- 数据库异常:AddDevice/DeleteDevice/UpdateDevInfo 使用事务,捕获_com_error后回滚并弹窗提示,优先检查SQL语句与权限。
- 文件传输失败:查看 ReceiveFile 的重试逻辑与 EndTransfer 终止流程,确认Zmodem握手与缓冲区大小。
- 远程设备状态不同步:核对远程设备集合维护逻辑(AddRemoteDevice/DeleteRemoteDevice),确保上下线通知正确到达。
章节来源
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L92-L125)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L203-L281)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L383-L483)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L682-L727)
- [DevManager.h](file://h/DevManager.h#L41-L66)
## 结论
设备管理模块通过“设备管理器-设备实体-句柄处理器-通信协议-视图/工具”的分层设计,实现了设备生命周期的完整闭环管理。其数据结构与句柄编码保证了高效稳定的设备索引;数据库事务与错误处理提升了可靠性;与项目/脚本管理器的协作使设备与数据、脚本的联动更加顺畅。在线/离线模式的差异化行为满足多场景需求,配合通信协议与错误码体系,为后续扩展(如云端托管、远程诊断)提供了坚实基础。
## 附录
- 关键调用路径参考
- 初始化设备链表:[DevManager.cpp](file://cpp/Managers/DevManager.cpp#L160-L201)
- 查询设备:[DevManager.cpp](file://cpp/Managers/DevManager.cpp#L48-L158)
- 在线/离线列表:[DevManager.cpp](file://cpp/Managers/DevManager.cpp#L486-L591)
- 更新设备参数:[DevManager.cpp](file://cpp/Managers/DevManager.cpp#L592-L642)
- 删除设备:[DevManager.cpp](file://cpp/Managers/DevManager.cpp#L383-L483)
- 设备详情展示:[Device.cpp](file://cpp/ProblemZone/Device.cpp#L115-L280)
- GR/AC信息展示:[Device.cpp](file://cpp/ProblemZone/Device.cpp#L511-L649)
- 文件接收/发送:[Device.cpp](file://cpp/ProblemZone/Device.cpp#L682-L727)
- 固件升级触发:[devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L47-L96)
- 升级执行与校验:[checkupdate.cpp](file://cpp/Tools/checkupdate.cpp#L1292-L1336)
@@ -0,0 +1,280 @@
# 设备连接与注册
<cite>
**本文档引用的文件**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
- [DevManager.h](file://h/DevManager.h)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp)
- [SComPort.h](file://h/SComPort.h)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp)
- [Device.h](file://h/Device.h)
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp)
- [DetcGD10Dev.h](file://h/DetcGD10Dev.h)
- [GD10OperCmd.cpp](file://cpp/Tools/GD10OperCmd.cpp)
- [GD10OperCmd.h](file://h/GD10OperCmd.h)
- [Global.cpp](file://cpp/Main/Global.cpp)
</cite>
## 目录
1. [引言](#引言)
2. [设备连接与枚举](#设备连接与枚举)
3. [设备注册与数据初始化](#设备注册与数据初始化)
4. [CDevice对象与链表管理](#cdevice对象与链表管理)
5. [连接状态与通知机制](#连接状态与通知机制)
6. [常见问题与解决方案](#常见问题与解决方案)
7. [结论](#结论)
## 引言
本文档详细阐述了GeomativeStudio软件中设备连接与注册功能的实现机制。核心组件`CDevManager`负责管理所有设备的生命周期,通过`SComPort`类与GD10设备建立串口通信,实现设备的自动检测、握手、注册和数据同步。文档将深入分析从物理连接检测到设备对象在内存中创建并注册的完整流程。
## 设备连接与枚举
设备连接的起点是检测物理设备的存在。系统通过`CDetcGD10Dev`类来检测连接的GD10设备。
```mermaid
flowchart TD
A[开始检测设备] --> B[枚举所有逻辑驱动器]
B --> C{驱动器类型为可移动磁盘?}
C --> |是| D[获取驱动器卷标]
D --> E{卷标为"GD10"或"GD20"?}
E --> |是| F[记录设备地址]
E --> |否| G[检查是否存在\\SD\\equipment目录]
G --> |存在| F
G --> |不存在| H[继续下一个驱动器]
C --> |否| H
H --> I{遍历完所有驱动器?}
I --> |否| B
I --> |是| J[返回设备地址]
```
**Diagram sources**
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp#L100-L173)
**Section sources**
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp#L61-L68)
- [DetcGD10Dev.h](file://h/DetcGD10Dev.h#L22)
### 串口通信建立
一旦检测到设备,`CDevManager`会通过`SComPort`类建立串口通信。`SComPort``OpenComm`方法负责初始化串口。
```mermaid
sequenceDiagram
participant CDevManager as CDevManager
participant SComPort as SComPort
participant OS as 操作系统
CDevManager->>SComPort : OpenComm("COM3")
SComPort->>OS : CreateFile("\\\\.\\COM3")
OS-->>SComPort : 返回设备句柄
SComPort->>SComPort : SetupComm(设置缓冲区大小)
SComPort->>SComPort : GetCommState(获取当前配置)
SComPort->>SComPort : 配置DCB结构体
SComPort->>SComPort : SetCommState(应用配置)
SComPort->>SComPort : SetCommMask(设置事件掩码)
SComPort-->>CDevManager : 返回TRUE(成功)
```
**Diagram sources**
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L127-L222)
- [SComPort.h](file://h/SComPort.h#L34)
**Section sources**
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L127-L222)
## 设备注册与数据初始化
当设备通过串口成功连接后,需要进行注册,将设备的物理信息同步到本地数据库。
### 设备信息读取
`CDevice`类的`GetDevInfo`方法负责从GD10设备读取其硬件和固件信息。
```mermaid
flowchart TD
A[调用GetDevInfo] --> B[发送"device_ex_info()"命令]
B --> C[等待设备响应]
C --> D{收到响应?}
D --> |是| E[解析响应数据]
E --> F[提取硬件版本(HWV)]
E --> G[提取固件版本(SWV)]
E --> H[提取生产日期(Mdate)]
E --> I[提取批次号(Mbatch)]
F --> J[更新CDevice对象属性]
G --> J
H --> J
I --> J
J --> K[将信息写入本地数据库]
K --> L[返回成功]
D --> |否| M[返回失败]
```
**Diagram sources**
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L1008-L1053)
**Section sources**
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L1008-L1113)
### 设备注册流程
设备信息读取成功后,`CDevManager`会调用`AddDevice`方法将设备正式注册到系统中。
```mermaid
classDiagram
class CDevManager {
+AddDevice(CDevice* pDev)
+InitialDevLinkList()
+GetDeviceByID(DWORD dwDevID)
}
class CDevice {
+m_szDevSN
+m_szModelNO
+m_szHWV
+m_szSWV
+m_uState
+m_dwID
}
class _ConnectionPtr {
+BeginTrans()
+CommitTrans()
+RollbackTrans()
}
CDevManager --> CDevice : 持有
CDevManager --> _ConnectionPtr : 使用
CDevManager --> CDevice : 注册
```
**Diagram sources**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L203-L280)
- [DevManager.h](file://h/DevManager.h#L30)
**Section sources**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L203-L280)
## CDevice对象与链表管理
`CDevManager`使用一个链表`m_devLinkList`来管理所有已注册的设备对象。
### 对象创建与注册
当一个新设备被发现时,`CDevManager`会创建一个`CDevice`对象,并将其添加到链表中。
```mermaid
sequenceDiagram
participant CDevManager as CDevManager
participant CDevice as CDevice
participant LinkList as CLinkList
CDevManager->>CDevice : new CDevice()
CDevice-->>CDevManager : 返回指针
CDevManager->>CDevManager : m_handleProcessor.GenerateHandle()
CDevManager->>LinkList : m_devLinkList.Add(句柄, CDevice指针)
LinkList-->>CDevManager : 添加成功
```
**Diagram sources**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L325-L343)
- [DevManager.h](file://h/DevManager.h#L63)
**Section sources**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L325-L343)
### 链表管理机制
`CLinkList`类提供了对设备对象的增删查改操作,`CDevManager`通过设备ID或句柄来访问特定的`CDevice`对象。
```mermaid
classDiagram
class CLinkList {
+Add(DWORD handle, CDevice* pDev)
+Delete(DWORD handle)
+Delete(CDevice* pDev)
+Get(DWORD handle) CDevice*
+Find(int index) CDevice*
+Length() int
+DeleteAll()
}
class CDevice {
+m_dwID
+m_szDevSN
+m_uState
}
CLinkList "1" --> "*" CDevice : 包含
```
**Diagram sources**
- [DevManager.h](file://h/DevManager.h#L63)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L48-L68)
**Section sources**
- [DevManager.h](file://h/DevManager.h#L63)
## 连接状态与通知机制
系统通过`CDevice`对象的`m_uState`属性来跟踪设备的连接状态,并通过UI层进行通知。
### 状态变更流程
设备的状态会随着连接过程而改变,从`PZ_STATE_NEW``PZ_STATE_ONLINE`
```mermaid
stateDiagram-v2
[*] --> PZ_STATE_OFFLINE
PZ_STATE_OFFLINE --> PZ_STATE_NEW : 设备被发现
PZ_STATE_NEW --> PZ_STATE_ONLINE : 注册成功
PZ_STATE_NEW --> PZ_STATE_OFFLINE : 注册失败
PZ_STATE_ONLINE --> PZ_STATE_OFFLINE : 连接断开
```
**Diagram sources**
- [Device.h](file://h/Device.h#L89)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L75-L77)
**Section sources**
- [Device.h](file://h/Device.h#L89)
### UI层响应
当设备状态发生变化时,UI层会更新设备列表视图,显示最新的设备信息。
```mermaid
sequenceDiagram
participant CDevice as CDevice
participant CDevManager as CDevManager
participant UI as UI界面
CDevice->>CDevice : SetState(PZ_STATE_ONLINE)
CDevice->>CDevManager : 通知状态变更
CDevManager->>UI : 发送WM_DEVICE_STATE_CHANGED消息
UI->>UI : 更新设备列表
UI->>UI : 刷新设备详细信息
```
**Diagram sources**
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L75-L77)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L489-L507)
**Section sources**
- [Device.cpp](file://cpp/ProblemZone/Device.cpp#L75-L77)
## 常见问题与解决方案
在设备连接过程中可能会遇到各种问题,系统提供了相应的处理机制。
### 连接超时
如果在规定时间内未能收到设备的响应,则判定为连接超时。
**解决方案**:
1. 检查设备电源是否开启。
2. 检查USB线缆是否连接牢固。
3. 尝试更换USB端口或线缆。
4. 重启设备和软件。
### 端口占用
如果目标串口已被其他程序占用,则无法打开。
**解决方案**:
1. 关闭可能占用该串口的其他程序(如串口调试助手)。
2. 在设备管理器中检查端口状态。
3. 重启计算机以释放所有端口。
### 协议不匹配
如果设备固件版本过低,可能不支持当前软件的通信协议。
**解决方案**:
1. 检查设备固件版本。
2. 使用`IAP-GD10.bat`工具对设备进行固件升级。
3. 确保软件版本与设备固件版本兼容。
## 结论
GeomativeStudio的设备连接与注册功能通过`CDevManager``SComPort``CDevice`等核心类协同工作,实现了从物理设备检测、串口通信建立、设备信息读取、数据库注册到UI状态更新的完整流程。该设计具有良好的模块化和可维护性,能够稳定地管理GD10设备的连接生命周期。
@@ -0,0 +1,242 @@
# 任务参数配置
<cite>
**本文引用的文件**
- [DialCfgTaskPacket.h](file://h/DialCfgTaskPacket.h)
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp)
- [TaskDataOper.h](file://h/TaskDataOper.h)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [GeoMative.rc](file://GeoMative.rc)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件围绕任务参数配置功能进行深入文档化,重点聚焦于DialCfgTaskPacket对话框的UI组件与交互逻辑,涵盖:
- 循环次数、时间间隔、PLC ID等参数的配置与校验规则(循环次数与时间间隔范围为1-60000)。
- 任务选择下拉框的数据来源:通过CTaskDataOper::QueryTdBrowseInfo从数据库查询任务列表。
- 任务包属性的存储结构:涉及tdTaskPacket与tdTaskPacketInfo两张表的关联关系。
- 提供代码示例路径,展示OnInitDialog中初始化UI控件与OnOK中保存配置数据的具体实现。
## 项目结构
任务参数配置功能位于视图层(Views)与数据操作层(Operator)之间,UI由DialCfgTaskPacket负责,数据访问由TaskDataOper封装。
```mermaid
graph TB
subgraph "视图层"
DCP["DialCfgTaskPacket<br/>对话框"]
end
subgraph "数据访问层"
TDO["CTaskDataOper<br/>任务数据操作"]
end
subgraph "数据库"
TP["tdTaskPacket<br/>主表"]
TPI["tdTaskPacketInfo<br/>明细表"]
TD["td<br/>任务基础表"]
end
DCP --> TDO
TDO --> TD
TDO --> TP
TDO --> TPI
```
图表来源
- [DialCfgTaskPacket.h](file://h/DialCfgTaskPacket.h#L1-L54)
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L1-L177)
- [TaskDataOper.h](file://h/TaskDataOper.h#L297-L336)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L685-L716)
章节来源
- [DialCfgTaskPacket.h](file://h/DialCfgTaskPacket.h#L1-L54)
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L1-L177)
- [TaskDataOper.h](file://h/TaskDataOper.h#L297-L336)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L685-L716)
## 核心组件
- DialCfgTaskPacket:任务参数配置对话框,包含任务选择下拉框、任务列表、循环次数、时间间隔、PLC ID输入框及添加/删除按钮。
- CTaskDataOper:封装数据库访问,提供任务浏览信息查询、任务包属性查询、任务包信息查询以及任务包写入等接口。
章节来源
- [DialCfgTaskPacket.h](file://h/DialCfgTaskPacket.h#L1-L54)
- [TaskDataOper.h](file://h/TaskDataOper.h#L297-L336)
## 架构总览
DialCfgTaskPacket作为UI入口,调用CTaskDataOper完成数据库读写;数据库层面以tdTaskPacket为主表存储任务包属性(循环次数、时间间隔、PLC ID),以tdTaskPacketInfo为明细表存储任务包内任务序列(TaskID、TaskName、TaskPacketID);任务基础信息来源于td表。
```mermaid
sequenceDiagram
participant U as "用户"
participant D as "DialCfgTaskPacket"
participant O as "CTaskDataOper"
participant DB as "数据库"
U->>D : 打开“任务参数配置”对话框
D->>O : QueryTdBrowseInfo(查询任务列表)
O->>DB : SELECT td
DB-->>O : 返回任务列表
O-->>D : 返回任务列表
D->>D : 初始化下拉框与列表列头
U->>D : 输入循环次数/时间间隔/PLC ID
U->>D : 添加任务到列表
D->>D : 去重检查与序号更新
U->>D : 点击“保存”
D->>D : 参数校验(1-60000, PLC ID非空)
D->>O : InsertTaskPacketInfo(批量写入)
O->>DB : INSERT tdTaskPacket
O->>DB : DELETE tdTaskPacketInfo WHERE TaskPacketID=1
O->>DB : INSERT tdTaskPacketInfo (逐条)
DB-->>O : 提交事务
O-->>D : 写入成功
D-->>U : 显示保存结果
```
图表来源
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L123-L177)
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L206-L300)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L685-L716)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1085-L1140)
## 详细组件分析
### DialCfgTaskPacket 对话框
- UI控件
- 任务选择下拉框:用于选择可执行的任务项。
- 任务列表:显示已选任务序列,包含序号、任务名、任务ID三列。
- 按钮:添加、删除。
- 参数输入框:循环次数、时间间隔(分钟)、PLC ID。
- 初始化流程(OnInitDialog
- 查询任务列表并填充下拉框。
- 读取任务包属性(循环次数、时间间隔、PLC ID)并回填到对应输入框。
- 初始化任务列表列头与内容。
- 交互逻辑
- 添加:校验下拉框选中状态,去重检查后插入列表。
- 删除:选中行删除,末尾行删除时需重排序号。
- 保存:对循环次数、时间间隔进行范围校验(1-60000),对PLC ID进行非空校验;收集列表数据与参数,调用数据操作层写入数据库。
章节来源
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L47-L108)
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L123-L177)
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L206-L300)
- [DialCfgTaskPacket.h](file://h/DialCfgTaskPacket.h#L1-L54)
### 任务选择下拉框数据来源
- 数据源:CTaskDataOper::QueryTdBrowseInfo返回std::vector<STTdBrowseInfo>,其中包含任务名与任务ID。
- 下拉框填充:将任务名加入组合框,同时将任务ID存入SetItemData以便后续使用。
- 使用场景:添加任务时,根据下拉框当前选中项获取任务ID与任务名。
章节来源
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1013-L1083)
- [TaskDataOper.h](file://h/TaskDataOper.h#L297-L306)
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L123-L142)
### 任务包属性与存储结构
- 属性结构:STTaskPacketAttr包含循环次数、时间间隔、PLC ID三项。
- 存储位置:
- 主表:tdTaskPacket(主键字段MainID=1,存储循环次数、时间间隔、PLC ID)。
- 明细表:tdTaskPacketInfo(字段TaskPacketID=1,存储每个任务的TaskID与TaskName)。
- 写入策略:先写入tdTaskPacket,再清空tdTaskPacketInfo中TaskPacketID=1的旧记录,最后批量插入新任务序列,事务提交。
章节来源
- [TaskDataOper.h](file://h/TaskDataOper.h#L324-L335)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L685-L716)
### 参数验证规则
- 循环次数与时间间隔:必须为整数且在1至60000之间。
- PLC ID:必须非空。
- 重复任务:列表中不允许出现相同任务ID。
章节来源
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L206-L258)
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L110-L121)
### 代码示例路径
- OnInitDialog中初始化UI控件与读取任务包属性
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L123-L177)
- OnOK中保存配置数据
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L206-L300)
- 任务包写入数据库
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L685-L716)
章节来源
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L123-L177)
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L206-L300)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L685-L716)
## 依赖分析
- DialCfgTaskPacket依赖CTaskDataOper进行数据库读写。
- CTaskDataOper依赖ADO Recordset访问td、tdTaskPacket、tdTaskPacketInfo表。
- UI资源定义在GeoMative.rc中,包含对话框控件ID与布局。
```mermaid
classDiagram
class CDialCfgTaskPacket {
+DoDataExchange(pDX)
+OnInitDialog() bool
+OnOK() void
+OnButtonAdd() void
+OnButtonDel() void
-InitialTaskList() void
-IsRepeatTask(iTaskID) bool
-m_listTaskPacket
-m_cmbTaskName
}
class CTaskDataOper {
+QueryTdBrowseInfo(vt, bIsQueryTimerTd) void
+QueryTdBrowseInfo(vt, iSptType, iType, bIsQueryTimerTd) void
+QueryTaskPacketAttr(iLoopTime, iInterval, strPlcID) bool
+QueryTaskPacketInfo(vt) bool
+InsertTaskPacketInfo(vt, stAttr) bool
}
CDialCfgTaskPacket --> CTaskDataOper : "调用"
```
图表来源
- [DialCfgTaskPacket.h](file://h/DialCfgTaskPacket.h#L1-L54)
- [TaskDataOper.h](file://h/TaskDataOper.h#L297-L336)
章节来源
- [DialCfgTaskPacket.h](file://h/DialCfgTaskPacket.h#L1-L54)
- [TaskDataOper.h](file://h/TaskDataOper.h#L297-L336)
## 性能考虑
- 列表操作:删除末尾行时避免重排所有序号,仅在需要时更新后续行序号,降低O(n)更新成本。
- 数据库写入:批量插入tdTaskPacketInfo,减少多次往返;使用事务保证一致性。
- UI输入限制:对PLC ID设置最大长度,减少无效输入带来的处理开销。
章节来源
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L81-L108)
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L158-L160)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L685-L716)
## 故障排查指南
- 无法加载任务列表
- 检查CTaskDataOper::QueryTdBrowseInfo是否抛出异常或返回空集。
- 确认数据库连接正常,td表存在且包含有效记录。
- 保存失败
- 检查InsertTaskPacketInfo返回值与事务回滚日志。
- 确认循环次数、时间间隔、PLC ID均满足校验条件。
- 重复任务
- 确认IsRepeatTask逻辑正确,列表中不存在相同TaskID。
- UI无响应
- 检查消息映射与控件ID是否匹配(见资源定义)。
章节来源
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1013-L1083)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L685-L716)
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L206-L300)
## 结论
DialCfgTaskPacket通过CTaskDataOper实现了任务参数配置的完整闭环:从任务列表加载、参数输入与校验,到任务包属性与任务序列的持久化存储。其设计遵循清晰的职责分离与事务一致性保障,适合在实际工程中扩展与维护。
## 附录
- 控件ID与资源定义参考
- [GeoMative.rc](file://GeoMative.rc#L1925-L1941)
@@ -0,0 +1,286 @@
# 任务配置
<cite>
**本文档引用的文件**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
</cite>
## 目录
1. [项目结构](#项目结构)
2. [任务包配置流程](#任务包配置流程)
3. [任务与项目、测区的关联关系](#任务与项目测区的关联关系)
4. [任务配置数据的验证机制和错误处理策略](#任务配置数据的验证机制和错误处理策略)
5. [任务配置驱动脚本生成过程](#任务配置驱动脚本生成过程)
6. [任务配置API使用示例](#任务配置api使用示例)
## 项目结构
Geomative Studio项目的任务配置功能主要集中在`cpp/Views``cpp/Operator`目录下。核心文件包括`DialCfgTaskPacket.cpp`用于任务包配置的UI交互,`TaskDataOper.cpp`负责任务数据的数据库操作,以及`SptManager.cpp`管理脚本文件的创建和同步。
```mermaid
graph TB
subgraph "UI层"
DialCfgTaskPacket["DialCfgTaskPacket.cpp<br/>任务包配置对话框"]
end
subgraph "业务逻辑层"
TaskDataOper["TaskDataOper.cpp<br/>任务数据操作"]
SptManager["SptManager.cpp<br/>脚本管理"]
end
subgraph "数据层"
Database[(dptt数据库)]
end
DialCfgTaskPacket --> TaskDataOper
TaskDataOper --> Database
SptManager --> TaskDataOper
```
**Diagram sources**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
**Section sources**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
## 任务包配置流程
任务包配置功能通过`DialCfgTaskPacket`对话框实现,允许用户将多个测量任务组合成一个任务包进行管理。配置流程包括:
1. 初始化对话框时,从数据库查询所有可用任务并填充到下拉列表中
2. 用户选择任务后点击"添加"按钮,将选中的任务添加到任务包列表中
3. 用户可删除已添加的任务
4. 配置任务包的循环次数、时间间隔和PLC ID等属性
5. 保存配置时进行数据验证,确保参数在有效范围内
```mermaid
flowchart TD
Start([开始]) --> Init["初始化对话框"]
Init --> Query["查询可用任务"]
Query --> Display["显示任务下拉列表"]
Display --> Select["用户选择任务"]
Select --> Add["点击添加按钮"]
Add --> Check["检查任务是否重复"]
Check --> |是| Warn["提示任务已存在"]
Check --> |否| Insert["插入任务到列表"]
Insert --> Continue["继续添加其他任务?"]
Continue --> |是| Select
Continue --> |否| Config["配置循环参数"]
Config --> Validate["验证输入参数"]
Validate --> |无效| Error["显示错误信息"]
Validate --> |有效| Save["保存任务包配置"]
Save --> End([结束])
```
**Diagram sources**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp)
**Section sources**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp)
## 任务与项目、测区的关联关系
任务配置与项目、测区之间存在明确的层级关联关系。每个任务必须归属于一个测区,而测区又属于特定的项目。这种关系在dptt数据库中通过外键约束实现:
- `project`表存储项目信息
- `tz`表存储测区信息,包含指向`project`表的外键`PRID`
- `td`表存储任务信息,包含指向`tz`表的外键`TZID`
当创建新任务时,系统会自动获取默认测区ID,并将该ID与任务关联。这种设计确保了任务数据的组织结构清晰,便于按项目和测区进行数据管理和查询。
```mermaid
erDiagram
PROJECT {
uuid id PK
string PRname
timestamp create_time
}
TZ {
uuid id PK
string TzName
uuid PRID FK
timestamp create_time
}
TD {
uuid id PK
string TDname
uuid TZID FK
uuid SCID FK
int Ttype
int Stype
timestamp CreateTime
}
PROJECT ||--o{ TZ : "包含"
TZ ||--o{ TD : "包含"
```
**Diagram sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
**Section sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
## 任务配置数据的验证机制和错误处理策略
系统在任务配置过程中实施了严格的验证机制和错误处理策略,确保数据的完整性和有效性:
1. **输入验证**
- 循环次数必须在1-60000之间
- 时间间隔必须在1-60000之间
- PLC ID不能为空
2. **重复性检查**
- 添加任务时检查是否已存在相同任务ID,避免重复
3. **事务处理**
- 所有数据库操作都在事务中执行,确保数据一致性
- 操作失败时自动回滚事务
4. **异常处理**
- 使用try-catch捕获数据库操作异常
- 显示详细的错误信息给用户
5. **多语言支持**
- 根据系统语言设置显示相应的错误提示信息
```mermaid
flowchart TD
Start([开始保存]) --> ValidateLoop["验证循环次数"]
ValidateLoop --> |无效| ShowError1["显示范围错误"]
ValidateLoop --> |有效| ValidateInterval["验证时间间隔"]
ValidateInterval --> |无效| ShowError2["显示范围错误"]
ValidateInterval --> |有效| ValidatePLC["验证PLC ID"]
ValidatePLC --> |为空| ShowError3["显示不能为空"]
ValidatePLC --> |有效| BeginTrans["开始事务"]
BeginTrans --> InsertData["插入任务包数据"]
InsertData --> Commit["提交事务"]
Commit --> |成功| Success["显示保存成功"]
Commit --> |失败| Rollback["回滚事务"]
Rollback --> ShowError4["显示保存失败"]
```
**Diagram sources**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp)
**Section sources**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp)
## 任务配置驱动脚本生成过程
任务配置通过`SptManager``ProManager`的协作模式驱动后续的脚本生成过程。当任务配置完成后,系统会根据配置参数自动生成相应的测量脚本文件。
```mermaid
sequenceDiagram
participant UI as "用户界面"
participant TaskConfig as "任务配置"
participant SptManager as "SptManager"
participant ProManager as "ProManager"
participant Database as "数据库"
UI->>TaskConfig : 配置任务参数
TaskConfig->>Database : 保存任务配置
Database-->>TaskConfig : 保存成功
TaskConfig->>SptManager : 请求生成脚本
SptManager->>ProManager : 获取项目/测区信息
ProManager-->>SptManager : 返回项目结构
SptManager->>Database : 查询任务详情
Database-->>SptManager : 返回任务数据
SptManager->>SptManager : 生成脚本文件
SptManager->>Database : 保存脚本信息
Database-->>SptManager : 保存成功
SptManager-->>TaskConfig : 脚本生成完成
TaskConfig-->>UI : 显示操作结果
```
**Diagram sources**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
**Section sources**
- [SptManager.cpp](file://cpp/Managers/SptManager.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
## 任务配置API使用示例
以下是通过编程方式创建和修改任务参数的API使用示例:
```mermaid
classDiagram
class CTaskDataOper {
+Create1DTask(ST1DTaskParam, CString) int
+Create2DTask(ST2DTaskParam, CString) int
+Create3DTask(ST3DTaskParam, CString) int
+InsertTaskPacketInfo(vector~STTdBrowseInfo~, STTaskPacketAttr) bool
+QueryTaskPacketInfo(vector~STTdBrowseInfo~) bool
+QueryTaskPacketAttr(int&, int&, CString&) bool
}
class ST1DTaskParam {
+CString strTDName
+int iSptID
+CString strSptName
+int iSptType
+int iTestType
+int iStacking
+int iTxWave
+int iTxPeriod
+int iSAInterval
+CString strTestPlace
}
class ST2DTaskParam {
+CString strTDName
+int iSptID
+CString strSptName
+int iSptType
+int iTestType
+int iStacking
+int iTxWave
+int iTxPeriod
+int iSAInterval
+CString strTestPlace
+int iStartElec
+int iEndElec
+int iEAmount
+int iAR
+int iCableLayout
+int iSkipCable
+int iRollCnt
+float fEspace
+BYTE ucTestGRFlag
+UINT uiDevID
}
class ST3DTaskParam {
+CString strTDName
+int iSptID
+CString strSptName
+int iSptType
+int iTestType
+int iStacking
+int iTxWave
+int iTxPeriod
+int iSAInterval
+CString strTestPlace
+int iEAmount
+int iAR
+int iCableLayout
+int iSkipCable
+BYTE ucTestGRFlag
+UINT uiDevID
}
class STTaskPacketAttr {
+int iLoopTimes
+int iInterval
+CString strPlcID
}
CTaskDataOper --> ST1DTaskParam : "使用"
CTaskDataOper --> ST2DTaskParam : "使用"
CTaskDataOper --> ST3DTaskParam : "使用"
CTaskDataOper --> STTaskPacketAttr : "使用"
```
**Diagram sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
**Section sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
@@ -0,0 +1,249 @@
# 任务验证与存储
<cite>
**本文档引用的文件**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [TaskDataOper.h](file://h/TaskDataOper.h)
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp)
- [DialCfgTaskPacket.h](file://h/DialCfgTaskPacket.h)
</cite>
## 目录
1. [简介](#简介)
2. [CTaskDataOper类的作用](#ctaskdataoper类的作用)
3. [任务数据持久化机制](#任务数据持久化机制)
4. [InsertTaskPacketInfo方法分析](#inserttaskpacketinfo方法分析)
5. [数据验证流程](#数据验证流程)
6. [任务包配置数据存储结构](#任务包配置数据存储结构)
7. [错误处理策略](#错误处理策略)
8. [UI到数据库的完整流程示例](#ui到数据库的完整流程示例)
## 简介
本文档深入分析了GeomativeStudio软件中任务配置的验证与存储机制,重点阐述了CTaskDataOper类在任务数据持久化中的核心作用。文档详细描述了任务列表和属性信息如何通过InsertTaskPacketInfo方法写入数据库,包括对tdTaskPacket和tdTaskPacketInfo表的操作。同时,文档解释了数据验证流程、存储结构定义以及错误处理策略。
## CTaskDataOper类的作用
CTaskDataOper类是GeomativeStudio系统中负责任务数据操作的核心类,主要承担任务数据的持久化、查询、验证和管理功能。该类通过ADO数据库连接与后端数据库进行交互,实现了任务数据的增删改查操作。
该类的主要职责包括:
- 任务数据的创建与持久化
- 任务数据的查询与检索
- 任务数据的验证与去重
- 事务管理与错误处理
- 任务包配置的存储与读取
**Section sources**
- [TaskDataOper.h](file://h/TaskDataOper.h#L338-L445)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L42-L55)
## 任务数据持久化机制
任务数据持久化机制是系统确保任务配置信息可靠存储的关键组件。系统通过CTaskDataOper类提供的方法,将用户在UI界面配置的任务信息持久化到数据库中,确保数据的一致性和完整性。
持久化过程遵循以下原则:
- 使用数据库事务确保操作的原子性
- 通过外键约束维护数据完整性
- 采用参数化查询防止SQL注入
- 实现批量操作提高性能
系统主要涉及以下数据库表:
- td: 存储任务基本信息
- tdTaskPacket: 存储任务包主配置
- tdTaskPacketInfo: 存储任务包中包含的任务列表
**Section sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L679-L703)
- [TaskDataOper.h](file://h/TaskDataOper.h#L418-L420)
## InsertTaskPacketInfo方法分析
InsertTaskPacketInfo方法是任务包信息存储的核心方法,负责将任务列表和属性信息写入数据库。该方法实现了对tdTaskPacket和tdTaskPacketInfo表的批量插入操作。
```mermaid
flowchart TD
Start([开始]) --> BeginTrans["开始事务"]
BeginTrans --> DeleteMain["删除tdTaskPacket表中MainID=1的记录"]
DeleteMain --> InsertMain["插入新的任务包主配置"]
InsertMain --> DeleteDetail["删除tdTaskPacketInfo表中TaskPacketID=1的记录"]
DeleteDetail --> LoopStart["循环遍历任务列表"]
LoopStart --> InsertDetail["插入单个任务信息到tdTaskPacketInfo表"]
InsertDetail --> LoopCheck{"是否还有任务?"}
LoopCheck --> |是| LoopStart
LoopCheck --> |否| CommitTrans["提交事务"]
CommitTrans --> End([结束])
Exception["异常捕获"] --> RollbackTrans["回滚事务"]
RollbackTrans --> ReturnFalse["返回false"]
BeginTrans --> Exception
```
**Diagram sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L668-L714)
**Section sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L668-L714)
## 数据验证流程
系统实现了完善的数据验证流程,确保任务配置的准确性和唯一性。其中,防止重复添加任务是重要的验证逻辑之一。
### IsRepeatTask方法实现逻辑
IsRepeatTask方法用于验证任务是否已存在于任务包中,防止重复添加。该方法通过遍历UI界面上已添加的任务列表,检查新任务的ID是否已存在。
```mermaid
flowchart TD
Start([开始]) --> GetItemCount["获取任务列表项数"]
GetItemCount --> LoopStart["设置循环索引i=0"]
LoopStart --> CheckIndex{"i < 任务总数?"}
CheckIndex --> |否| ReturnFalse["返回false"]
CheckIndex --> |是| GetTaskID["获取第i项任务ID"]
GetTaskID --> CompareID{"任务ID匹配?"}
CompareID --> |是| ReturnTrue["返回true"]
CompareID --> |否| IncrementI["i++"]
IncrementI --> LoopStart
ReturnTrue --> End([结束])
ReturnFalse --> End
```
**Diagram sources**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L109-L121)
**Section sources**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L109-L121)
- [DialCfgTaskPacket.h](file://h/DialCfgTaskPacket.h#L47)
## 任务包配置数据存储结构
系统定义了清晰的数据结构来存储任务包配置信息,包括STTdBrowseInfo和STTaskPacketAttr两个关键数据结构。
### STTdBrowseInfo数据结构
该结构用于存储任务的基本浏览信息,包括任务ID和任务名称。
```mermaid
classDiagram
class STTdBrowseInfo {
+int iTaskID
+CString strTaskName
+STTdBrowseInfo()
}
```
**Diagram sources**
- [TaskDataOper.h](file://h/TaskDataOper.h#L297-L306)
### STTaskPacketAttr数据结构
该结构用于存储任务包的属性配置,包括循环次数、时间间隔和PLC ID。
```mermaid
classDiagram
class STTaskPacketAttr {
+int iLoopTimes
+int iInterval
+CString strPlcID
+STTaskPacketAttr()
}
```
**Diagram sources**
- [TaskDataOper.h](file://h/TaskDataOper.h#L324-L335)
### 数据库表结构
系统使用两个数据库表来存储任务包配置:
#### tdTaskPacket表
存储任务包的主配置信息。
| 字段名 | 数据类型 | 描述 |
|--------|---------|------|
| MainID | Integer | 主键,固定为1 |
| LoopTimes | Integer | 循环次数 |
| Interval | Integer | 时间间隔(秒) |
| PLCID | Text | PLC设备ID |
**Section sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L685-L687)
#### tdTaskPacketInfo表
存储任务包中包含的具体任务列表。
| 字段名 | 数据类型 | 描述 |
|--------|---------|------|
| TaskID | Integer | 任务ID |
| TaskName | Text | 任务名称 |
| TaskPacketID | Integer | 任务包ID,固定为1 |
**Section sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L697-L699)
## 错误处理策略
系统实现了完善的错误处理策略,确保在数据保存失败时能够正确回滚并提供用户友好的提示信息。
### 事务回滚机制
系统使用数据库事务来确保数据操作的原子性。当任何操作失败时,系统会自动回滚事务,保持数据一致性。
```mermaid
sequenceDiagram
participant UI as "用户界面"
participant Logic as "业务逻辑"
participant DB as "数据库"
UI->>Logic : 请求保存任务包
Logic->>DB : 开始事务
DB-->>Logic : 事务开始
Logic->>DB : 删除旧配置
DB-->>Logic : 删除完成
Logic->>DB : 插入新配置
DB-->>Logic : 插入完成
alt 操作成功
Logic->>DB : 提交事务
DB-->>Logic : 提交成功
Logic->>UI : 显示"保存成功"
else 操作失败
Logic->>DB : 回滚事务
DB-->>Logic : 回滚完成
Logic->>UI : 显示错误信息
end
```
**Diagram sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L677-L712)
### 用户提示信息
系统根据不同的错误情况提供相应的用户提示信息:
| 错误类型 | 中文提示 | 英文提示 |
|---------|--------|--------|
| 保存失败 | 保存失败 | Save failed |
| 循环次数无效 | 循环次数的值必须在1-60000之间 | The value of LoopTimes should between 1 to 60000 |
| 时间间隔无效 | 时间间隔的值必须在1-60000之间 | The value of Interval Time should between 1 to 60000 |
| PLC ID为空 | 请输入PLC ID | Please input plcid |
| 任务重复 | 任务已存在 | This task has been exist |
**Section sources**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L285-L297)
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L222-L235)
## UI到数据库的完整流程示例
以下是从UI数据收集到数据库存储的完整流程示例:
```mermaid
flowchart TD
UIStart([用户界面]) --> SelectTask["用户选择任务"]
SelectTask --> ValidateTask["验证任务是否重复"]
ValidateTask --> |重复| ShowError["显示'任务已存在'"]
ValidateTask --> |不重复| AddToList["添加到任务列表"]
AddToList --> ConfigureAttr["配置任务包属性"]
ConfigureAttr --> ValidateInput["验证输入参数"]
ValidateInput --> |无效| ShowInputError["显示参数错误"]
ValidateInput --> |有效| CollectData["收集UI数据"]
CollectData --> CreateStruct["创建STTdBrowseInfo和STTaskPacketAttr结构"]
CreateStruct --> CallInsert["调用InsertTaskPacketInfo方法"]
CallInsert --> DBStart["开始数据库操作"]
DBStart --> BeginTrans["开始事务"]
BeginTrans --> DeleteOld["删除旧配置"]
DeleteOld --> InsertNew["插入新配置"]
InsertNew --> Commit["提交事务"]
Commit --> |成功| ShowSuccess["显示'保存成功'"]
Commit --> |失败| Rollback["回滚事务"]
Rollback --> ShowDBError["显示'保存失败'"]
```
**Diagram sources**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L206-L300)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L668-L714)
**Section sources**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L206-L300)
@@ -0,0 +1,334 @@
# 测区创建与配置
<cite>
**本文引用的文件**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [TestingZone.cpp](file://cpp/ProblemZone/TestingZone.cpp)
- [TestingZone.h](file://h/TestingZone.h)
- [opcreatetzdlg.cpp](file://cpp/Views/opcreatetzdlg.cpp)
- [opcreatetzdlg.h](file://h/opcreatetzdlg.h)
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp)
- [testzone.xml](file://CACHE/testzone.xml)
- [project.xml](file://CACHE/project.xml)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件围绕“测区创建与配置”主题,系统梳理GeomativeStudio中测区(Testing Zone)的创建流程、用户输入校验、测区类型(TZtype)业务规则、与数据库的交互、以及测区配置界面(如DialCfgTerrain)的数据绑定与持久化策略。重点说明:
- CProManager类中创建新测区的核心方法调用链与事务控制
- TestingZone类如何构建测区元数据模型及其字段约束
- 测区配置界面的UI逻辑与数据绑定机制
- 用户配置参数如何序列化并持久化到testzone.xml文件
- 常见配置错误的排查与修复建议
## 项目结构
与测区创建与配置直接相关的模块分布如下:
- 管理层:CProManager(工程与测区管理)
- 模型层:CTestingZone(测区元数据封装)
- 视图层:opcreatetzdlg(创建测区对话框)、DialCfgTerrain(地形配置对话框)
- 缓存与持久化:CACHE目录下的testzone.xml、project.xml
```mermaid
graph TB
subgraph "管理层"
PM["CProManager<br/>测区创建/下发/同步"]
end
subgraph "模型层"
TZ["CTestingZone<br/>测区元数据"]
end
subgraph "视图层"
Dlg["COpCreateTzDlg<br/>创建测区对话框"]
Terrain["CDialCfgTerrain<br/>地形配置对话框"]
end
subgraph "缓存与持久化"
XML_TZ["CACHE/testzone.xml"]
XML_PRJ["CACHE/project.xml"]
end
Dlg --> PM
PM --> TZ
PM --> XML_TZ
PM --> XML_PRJ
Terrain --> XML_TZ
```
图表来源
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L945-L1013)
- [TestingZone.cpp](file://cpp/ProblemZone/TestingZone.cpp#L1-L82)
- [opcreatetzdlg.cpp](file://cpp/Views/opcreatetzdlg.cpp#L54-L92)
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L539-L693)
- [testzone.xml](file://CACHE/testzone.xml#L1-L57)
- [project.xml](file://CACHE/project.xml#L1-L22)
章节来源
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L945-L1013)
- [TestingZone.cpp](file://cpp/ProblemZone/TestingZone.cpp#L1-L82)
- [opcreatetzdlg.cpp](file://cpp/Views/opcreatetzdlg.cpp#L54-L92)
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L539-L693)
- [testzone.xml](file://CACHE/testzone.xml#L1-L57)
- [project.xml](file://CACHE/project.xml#L1-L22)
## 核心组件
- CProManager:提供测区创建、设备下发、同步等功能;负责数据库事务与设备通信。
- CTestingZone:封装测区元数据(名称、类型、创建日期、描述、位置、CN等),用于UI展示与业务逻辑。
- COpCreateTzDlg:测区创建对话框,负责用户输入校验与TZtype赋值。
- CDialCfgTerrain:地形配置对话框,负责地形数据的导入、校验与写入原始dat文件。
章节来源
- [TestingZone.h](file://h/TestingZone.h#L1-L33)
- [TestingZone.cpp](file://cpp/ProblemZone/TestingZone.cpp#L1-L82)
- [opcreatetzdlg.h](file://h/opcreatetzdlg.h#L1-L53)
- [opcreatetzdlg.cpp](file://cpp/Views/opcreatetzdlg.cpp#L54-L92)
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L539-L693)
## 架构总览
测区创建与下发的关键流程如下:
- 用户通过对话框输入测区基本信息(名称、类型、日期、位置、描述)
- CProManager在数据库中插入测区记录并生成唯一CN
- 将测区元数据序列化为testzone.xml并下发至设备
- 设备侧接收后,写入dev_syn_td标记同步状态
```mermaid
sequenceDiagram
participant U as "用户"
participant D as "COpCreateTzDlg"
participant PM as "CProManager"
participant DB as "数据库"
participant DEV as "设备"
participant FS as "本地文件系统"
U->>D : 打开创建测区对话框
D->>D : 输入校验与TZtype赋值
D-->>PM : 返回测区参数
PM->>DB : 插入tz记录并生成CN
PM->>FS : 生成testzone.xml
PM->>DEV : 下发testzone.xml
DEV-->>PM : 返回下发结果
PM->>DB : 写入dev_syn_td(IsSyned=true)
PM-->>U : 创建完成/错误提示
```
图表来源
- [opcreatetzdlg.cpp](file://cpp/Views/opcreatetzdlg.cpp#L54-L92)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L945-L1013)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L800-L943)
- [testzone.xml](file://CACHE/testzone.xml#L1-L57)
章节来源
- [opcreatetzdlg.cpp](file://cpp/Views/opcreatetzdlg.cpp#L54-L92)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L945-L1013)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L800-L943)
## 详细组件分析
### CProManager类:创建新测区的核心流程
- 对话框调用与参数收集
- 通过COpCreateTzDlg收集测区名称、位置、描述、创建日期等参数。
- 对话框内部将TZtype固定为“3”,体现“默认测区”的强制逻辑。
- 数据库插入与ID回填
- 使用Command执行INSERT语句,插入tz记录并返回ID。
- 通过查询再次确认ID,保证后续流程使用正确ID。
- XML生成与下发
- 以CMarkup生成testzone.xml,包含type、location、desc、create_date、test_date、cn、testzone_name等节点。
- 调用AddTzInDev创建设备端测区目录与类型标记,随后通过SendFile下发testzone.xml。
- 同步状态维护
- 下发成功后,向dev_syn_td写入IsSyned=true,标记该测区已同步。
```mermaid
flowchart TD
Start(["开始"]) --> OpenDlg["打开测区创建对话框"]
OpenDlg --> Validate["输入校验<br/>名称必填"]
Validate --> |通过| InsertTZ["插入tz记录"]
Validate --> |不通过| Error["提示错误并终止"]
InsertTZ --> GenXML["生成testzone.xml"]
GenXML --> SendFile["下发testzone.xml到设备"]
SendFile --> |成功| MarkSync["写入dev_syn_td(IsSyned=true)"]
SendFile --> |失败| Rollback["删除设备端测区并回滚"]
MarkSync --> End(["结束"])
Error --> End
Rollback --> End
```
图表来源
- [opcreatetzdlg.cpp](file://cpp/Views/opcreatetzdlg.cpp#L54-L92)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L945-L1013)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L800-L943)
章节来源
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L945-L1013)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L800-L943)
### TestingZone类:测区元数据模型
- 字段定义与约束
- 名称、创建日期、描述、位置、CN、TZtype等均来自数据库tz表查询结果。
- ShowDetailInfo根据TZtype映射为“1D VES | 2D ERI”、“3D ERT”或“All Type”,用于UI展示。
- 数据来源
- 通过ADO Recordset按ID查询tz表,填充成员变量。
- 使用场景
- 在工程树或详情面板中展示测区信息;与CProManager配合进行测区同步。
```mermaid
classDiagram
class 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
+ShowDetailInfo(tzDetailList) bool
+CTestingZone(dwID, connection)
+~CTestingZone()
}
```
图表来源
- [TestingZone.h](file://h/TestingZone.h#L1-L33)
- [TestingZone.cpp](file://cpp/ProblemZone/TestingZone.cpp#L1-L82)
章节来源
- [TestingZone.h](file://h/TestingZone.h#L1-L33)
- [TestingZone.cpp](file://cpp/ProblemZone/TestingZone.cpp#L1-L82)
### COpCreateTzDlg:测区创建对话框与TZtype业务规则
- 用户输入验证
- 名称必填校验;其他字段长度限制(位置、描述)。
- TZtype强制逻辑
- 对话框内部将m_edTzType硬编码为“3”,即“默认测区”类型。
- 这意味着创建新测区时,类型必须为3,否则后续流程会报错或不一致。
- 交互细节
- OnOK中完成UpdateData与校验,随后设置TZtype并关闭对话框。
章节来源
- [opcreatetzdlg.cpp](file://cpp/Views/opcreatetzdlg.cpp#L54-L92)
- [opcreatetzdlg.h](file://h/opcreatetzdlg.h#L1-L53)
### DialCfgTerrain:地形配置界面与数据绑定
- UI与数据绑定
- 通过DoDataExchange绑定控件,支持列表项编辑、删除、新增等操作。
- 支持从dat文件导入地形数据,写入指定位置并追加结束符。
- 输入校验与写入策略
- 校验dat文件头三行是否包含有效装置类型信息;禁止Wenner(gamma)与1D装置写入地形数据。
- 根据装置类型确定末尾0的个数,确保文件格式正确。
- 写入格式包含“地形数据标志”“点数”“各点坐标”“首电极对应点号”“若干0结束符”。
```mermaid
flowchart TD
Enter(["进入地形配置"]) --> Import["导入dat文件"]
Import --> Parse["解析文件头信息<br/>校验装置类型"]
Parse --> |不合法| Warn["提示错误并终止"]
Parse --> |合法| Edit["编辑地形点列表"]
Edit --> Save["保存到原文件"]
Save --> Write["写入标志/点数/坐标/首电极点号/结束符"]
Write --> Done(["完成"])
Warn --> Done
```
图表来源
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L539-L693)
章节来源
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L539-L693)
### XML文件生成规则与持久化
- testzone.xml生成规则
- 根元素为testzone,子元素包含type、location、desc、create_date、create_time、test_date、test_time、cn、testzone_name、testzone_3D_script、vess、eris、erts等。
- 元素层级清晰,便于设备侧解析与同步。
- project.xml生成规则
- 根元素为project,包含工程相关信息及testzones节点,其中包含多个测区的TYPE与CN。
- 持久化路径
- 本地缓存路径:CACHE/projects/{PrCN}/{TzCN}/testzone.xml
- 设备侧路径:/SD/projects/{PrCN}/{TzCN}/testzone.xml
章节来源
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L800-L943)
- [testzone.xml](file://CACHE/testzone.xml#L1-L57)
- [project.xml](file://CACHE/project.xml#L1-L22)
## 依赖关系分析
- CProManager依赖ADO数据库连接与设备通信接口,负责事务控制与文件下发。
- CTestingZone依赖数据库查询结果,用于UI展示与业务逻辑。
- COpCreateTzDlg与DialCfgTerrain分别负责用户输入与地形数据配置,最终驱动CProManager完成测区创建与下发。
- XML文件作为中间介质,贯穿本地与设备两端的数据交换。
```mermaid
graph LR
Dlg["COpCreateTzDlg"] --> PM["CProManager"]
Terrain["CDialCfgTerrain"] --> PM
PM --> DB["数据库"]
PM --> XML["testzone.xml"]
PM --> DEV["设备"]
TZ["CTestingZone"] --> DB
```
图表来源
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L945-L1013)
- [TestingZone.cpp](file://cpp/ProblemZone/TestingZone.cpp#L1-L82)
- [opcreatetzdlg.cpp](file://cpp/Views/opcreatetzdlg.cpp#L54-L92)
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L539-L693)
章节来源
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L945-L1013)
- [TestingZone.cpp](file://cpp/ProblemZone/TestingZone.cpp#L1-L82)
- [opcreatetzdlg.cpp](file://cpp/Views/opcreatetzdlg.cpp#L54-L92)
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L539-L693)
## 性能考量
- 数据库事务:CProManager在下发成功后才提交事务,避免半写状态;失败时回滚并清理设备端测区,减少资源浪费。
- 文件IO:XML生成与下发采用一次性写入,避免频繁小块写入;地形文件写入采用定位与覆盖策略,减少磁盘碎片。
- UI响应:对话框在关键校验处短路返回,降低无效计算;列表控件批量更新,提升渲染效率。
## 故障排查指南
- 测区类型设置错误
- 现象:创建测区时报TZType错误或设备端同步失败。
- 原因:对话框内部强制TZtype为“3”,若外部逻辑绕过对话框,可能导致类型不一致。
- 处理:确保通过COpCreateTzDlg创建测区,或在调用CProManager前显式设置TZtype为“3”。
- 必填字段缺失
- 现象:对话框提示名称为空或校验失败。
- 处理:完善名称、位置、描述等字段后再提交;注意长度限制。
- 地形文件写入失败
- 现象:写地形数据到原文件失败或未找到结束符。
- 原因:dat文件格式不符合要求、装置类型不支持写地形、首电极点号越界。
- 处理:检查文件头三行、装置类型合法性、点号范围;确保末尾0个数符合约定。
- 下发失败
- 现象:设备返回失败或本地提示发送失败。
- 处理:检查设备通信状态、路径权限、文件完整性;必要时删除设备端测区并重试。
- 同步状态异常
- 现象:dev_syn_td中IsSyned未置位或置位错误。
- 处理:确认下发成功后是否执行写入dev_syn_td;若失败则回滚并清理设备端测区。
章节来源
- [opcreatetzdlg.cpp](file://cpp/Views/opcreatetzdlg.cpp#L54-L92)
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L539-L693)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L800-L943)
## 结论
- 测区创建流程由对话框输入、数据库插入、XML生成与下发、同步状态维护构成,CProManager承担核心协调职责。
- TestingZone提供稳定的测区元数据封装,支撑UI展示与业务逻辑。
- DialCfgTerrain负责地形配置,严格遵循文件格式规范,保障设备侧可正确解析。
- TZtype强制为“3”的设计体现了默认测区的业务规则,应严格遵守以避免后续错误。
## 附录
- 关键流程参考路径
- [创建测区对话框](file://cpp/Views/opcreatetzdlg.cpp#L54-L92)
- [创建测区数据库流程](file://cpp/Managers/ProManager.cpp#L945-L1013)
- [下发测区XML流程](file://cpp/Managers/ProManager.cpp#L800-L943)
- [测区元数据模型](file://cpp/ProblemZone/TestingZone.cpp#L1-L82)
- [地形配置与写入](file://cpp/Views/DialCfgTerrain.cpp#L539-L693)
- [测区XML样例](file://CACHE/testzone.xml#L1-L57)
- [工程XML样例](file://CACHE/project.xml#L1-L22)
@@ -0,0 +1,250 @@
# 测区数据同步
<cite>
**本文档引用的文件**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [SynOperator.cpp](file://cpp/Operator/SynOperator.cpp)
- [UpdateDataBase.cpp](file://cpp/Operator/UpdateDataBase.cpp)
- [FileTransfer.cpp](file://cpp/Tools/FileTransfer.cpp)
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp)
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp)
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp)
- [OnLineSynTdDlg.cpp](file://cpp/Views/OnLineSynTdDlg.cpp)
- [OnLineSynDevDlg.cpp](file://cpp/Views/OnLineSynDevDlg.cpp)
- [OpSynDlg.cpp](file://cpp/Views/OpSynDlg.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
</cite>
## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 引言
本文档全面构建了测区数据同步机制的技术文档,重点描述了CProManager如何协调FileTransfer和UpdateDataBase组件实现测区数据在本地应用与GD10设备间的双向同步。详细说明了同步协议的实现细节,包括数据包格式、传输校验机制(如CRC16/CRC32)和断点续传逻辑。解释了同步过程中对testzone.xml文件的读取、解析和更新流程,以及如何确保设备端与PC端测区数据的一致性。分析了同步失败的异常处理策略,如网络中断、设备无响应等情况下的重试机制和错误码定义。提供了性能优化建议,包括大数据量测区的分批传输策略和同步进度的UI反馈实现。文档包含实际同步日志的分析示例,帮助开发者诊断常见同步问题。
## 项目结构
项目结构显示了测区数据同步相关的文件和目录,包括CACHE、DB、Install、LOG、Release、cpp、h、res、tools等目录。关键文件包括ProManager.cpp、SynOperator.cpp、UpdateDataBase.cpp、FileTransfer.cpp等,这些文件实现了测区数据同步的核心功能。
```mermaid
graph TD
A[GeomativeStudio] --> B[CACHE]
A --> C[DB]
A --> D[Install]
A --> E[LOG]
A --> F[Release]
A --> G[cpp]
A --> H[h]
A --> I[res]
A --> J[tools]
G --> K[Managers]
G --> L[Operator]
G --> M[Tools]
G --> N[Views]
K --> O[ProManager.cpp]
L --> P[SynOperator.cpp]
L --> Q[UpdateDataBase.cpp]
M --> R[FileTransfer.cpp]
M --> S[Crc16.cpp]
M --> T[Crc32.cpp]
N --> U[OnLineSynTdDlg.cpp]
N --> V[OnLineSynDevDlg.cpp]
N --> W[OpSynDlg.cpp]
```
**Diagram sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [SynOperator.cpp](file://cpp/Operator/SynOperator.cpp)
- [UpdateDataBase.cpp](file://cpp/Operator/UpdateDataBase.cpp)
- [FileTransfer.cpp](file://cpp/Tools/FileTransfer.cpp)
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp)
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp)
- [OnLineSynTdDlg.cpp](file://cpp/Views/OnLineSynTdDlg.cpp)
- [OnLineSynDevDlg.cpp](file://cpp/Views/OnLineSynDevDlg.cpp)
- [OpSynDlg.cpp](file://cpp/Views/OpSynDlg.cpp)
**Section sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [SynOperator.cpp](file://cpp/Operator/SynOperator.cpp)
- [UpdateDataBase.cpp](file://cpp/Operator/UpdateDataBase.cpp)
- [FileTransfer.cpp](file://cpp/Tools/FileTransfer.cpp)
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp)
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp)
- [OnLineSynTdDlg.cpp](file://cpp/Views/OnLineSynTdDlg.cpp)
- [OnLineSynDevDlg.cpp](file://cpp/Views/OnLineSynDevDlg.cpp)
- [OpSynDlg.cpp](file://cpp/Views/OpSynDlg.cpp)
## 核心组件
核心组件包括CProManager、CSynOperator、CUpdateDataBase、FileTransfer、Crc16、Crc32等类,这些类实现了测区数据同步的核心功能。CProManager负责管理工程和测区,CSynOperator负责同步操作,CUpdateDataBase负责数据库更新,FileTransfer负责文件传输,Crc16和Crc32负责数据校验。
**Section sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [SynOperator.cpp](file://cpp/Operator/SynOperator.cpp)
- [UpdateDataBase.cpp](file://cpp/Operator/UpdateDataBase.cpp)
- [FileTransfer.cpp](file://cpp/Tools/FileTransfer.cpp)
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp)
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp)
## 架构概述
测区数据同步机制的架构包括本地应用、GD10设备、网络通信、文件传输、数据校验等组件。CProManager协调FileTransfer和UpdateDataBase组件,实现测区数据在本地应用与GD10设备间的双向同步。
```mermaid
graph TD
A[本地应用] --> B[CProManager]
B --> C[FileTransfer]
B --> D[UpdateDataBase]
C --> E[GD10设备]
D --> F[数据库]
E --> G[网络通信]
C --> H[Crc16]
C --> I[Crc32]
```
**Diagram sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [FileTransfer.cpp](file://cpp/Tools/FileTransfer.cpp)
- [UpdateDataBase.cpp](file://cpp/Operator/UpdateDataBase.cpp)
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp)
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp)
## 详细组件分析
### CProManager分析
CProManager类负责管理工程和测区,包括创建工程、创建测区、同步数据等操作。它通过调用FileTransfer和UpdateDataBase组件实现测区数据的同步。
```mermaid
classDiagram
class CProManager {
+ShowTzList()
+GetDMS()
+ShowProList()
+CreateProjectInDB()
+InsertDefaultTzToProject()
+CreateProjectInDev()
+CreateDefaultTzInDev()
+CreateTzInDev()
}
```
**Diagram sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
### CSynOperator分析
CSynOperator类负责同步操作,包括同步测区数据、同步任务数据等。它通过调用CProManager和FileTransfer组件实现数据同步。
```mermaid
classDiagram
class CSynOperator {
+Syn()
+InitialSynDlg()
}
```
**Diagram sources**
- [SynOperator.cpp](file://cpp/Operator/SynOperator.cpp)
### CUpdateDataBase分析
CUpdateDataBase类负责数据库更新,包括更新数据库版本、更新数据库结构等。它通过解析XML文件实现数据库的更新。
```mermaid
classDiagram
class CUpdateDataBase {
+QueryPreVersion()
+CheckNecessaryVersion()
+WriteVersionToDB()
+GetDBUpdatesInfo()
+ParserUpdateDBXml()
+AddDBTable()
+DeleteDBTable()
+AddTableCol()
+ModifyTableCol()
+ModifyDBTable()
}
```
**Diagram sources**
- [UpdateDataBase.cpp](file://cpp/Operator/UpdateDataBase.cpp)
### FileTransfer分析
FileTransfer类负责文件传输,包括发送文件、接收文件等。它通过调用底层通信接口实现文件的传输。
```mermaid
classDiagram
class FileTransfer {
+error()
+status()
}
```
**Diagram sources**
- [FileTransfer.cpp](file://cpp/Tools/FileTransfer.cpp)
### Crc16和Crc32分析
Crc16和Crc32类负责数据校验,包括计算CRC16和CRC32校验码。它们通过查表法实现高效的校验码计算。
```mermaid
classDiagram
class Crc16 {
+table[256]
+initialized
+Crc16()
}
class Crc32 {
+table[256]
+initialized
+Crc32()
}
```
**Diagram sources**
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp)
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp)
**Section sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [SynOperator.cpp](file://cpp/Operator/SynOperator.cpp)
- [UpdateDataBase.cpp](file://cpp/Operator/UpdateDataBase.cpp)
- [FileTransfer.cpp](file://cpp/Tools/FileTransfer.cpp)
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp)
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp)
## 依赖分析
测区数据同步机制的依赖包括本地应用、GD10设备、网络通信、文件传输、数据校验等。CProManager依赖于FileTransfer和UpdateDataBase组件,FileTransfer依赖于Crc16和Crc32组件。
```mermaid
graph TD
A[CProManager] --> B[FileTransfer]
A --> C[UpdateDataBase]
B --> D[Crc16]
B --> E[Crc32]
```
**Diagram sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [FileTransfer.cpp](file://cpp/Tools/FileTransfer.cpp)
- [UpdateDataBase.cpp](file://cpp/Operator/UpdateDataBase.cpp)
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp)
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp)
## 性能考虑
为了提高测区数据同步的性能,可以采用分批传输策略,将大数据量的测区数据分成多个小批次进行传输。同时,可以通过UI反馈显示同步进度,提高用户体验。
## 故障排除指南
同步失败的常见原因包括网络中断、设备无响应、数据校验失败等。可以通过重试机制和错误码定义来处理这些异常情况。例如,当网络中断时,可以等待网络恢复后重新尝试同步;当设备无响应时,可以检查设备连接状态并重新连接。
**Section sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [SynOperator.cpp](file://cpp/Operator/SynOperator.cpp)
- [UpdateDataBase.cpp](file://cpp/Operator/UpdateDataBase.cpp)
- [FileTransfer.cpp](file://cpp/Tools/FileTransfer.cpp)
- [Crc16.cpp](file://cpp/Tools/Crc16.cpp)
- [Crc32.cpp](file://cpp/Tools/Crc32.cpp)
## 结论
本文档详细描述了测区数据同步机制的实现细节,包括核心组件、架构概述、详细组件分析、依赖分析、性能考虑和故障排除指南。通过本文档,开发者可以更好地理解和实现测区数据同步功能。
@@ -0,0 +1,234 @@
# 测区管理
<cite>
**本文档引用的文件**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [TestingZone.cpp](file://cpp/ProblemZone/TestingZone.cpp)
- [TestingZone.h](file://h/TestingZone.h)
- [opcreatetzdlg.cpp](file://cpp/Views/opcreatetzdlg.cpp)
- [opcreatetzdlg.h](file://h/opcreatetzdlg.h)
- [appdatatzlistview.cpp](file://cpp/Views/appdatatzlistview.cpp)
- [database_modify.xml](file://database_modify.xml)
</cite>
## 目录
1. [项目与测区层级关系](#项目与测区层级关系)
2. [CProManager::ShowTzList方法分析](#cpromanagershowtzlist方法分析)
3. [测区类型(TZtype)枚举值及业务含义](#测区类型tztype枚举值及业务含义)
4. [测区配置数据持久化机制](#测区配置数据持久化机制)
5. [测区创建完整性校验流程](#测区创建完整性校验流程)
6. [测区数据模型字段说明](#测区数据模型字段说明)
## 项目与测区层级关系
在GeomativeStudio系统中,项目与测区之间存在明确的父子层级关系。每个项目可以包含多个测区,但每个测区只能属于一个项目。这种关系通过数据库中的外键约束实现,其中测区表(tz)中的PRID字段引用项目表(project)的ID字段。
项目作为数据管理的基本单元,包含了测区的集合。当用户选择一个项目时,系统会根据该项目的句柄查询其下属的所有测区,并在UI界面上展示这些测区列表。这种层级结构确保了数据组织的逻辑性和一致性,同时也便于数据的同步和管理。
项目与测区的关系还体现在设备端的数据同步过程中。当项目被同步到设备时,其包含的测区也会被同步。系统通过dev_syn_td表来跟踪项目和测区在设备上的同步状态,其中PRCN字段对应项目的CN码,TzCN字段对应测区的CN码。
**Section sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L33-L37)
- [TestingZone.cpp](file://cpp/ProblemZone/TestingZone.cpp#L18-L44)
## CProManager::ShowTzList方法分析
CProManager::ShowTzList方法负责根据项目句柄查询数据库并填充测区列表控件。该方法首先通过项目句柄获取对应的项目ID,然后执行SQL查询语句从数据库中获取该项目下的所有测区信息。
```mermaid
flowchart TD
Start([开始]) --> GetProjectID["从项目句柄获取项目ID"]
GetProjectID --> CheckItemCount{"列表项数不为0?"}
CheckItemCount --> |是| DeleteAllItems["删除所有列表项"]
CheckItemCount --> |否| BuildSQLQuery
DeleteAllItems --> BuildSQLQuery
BuildSQLQuery --> ExecuteQuery["执行SQL查询"]
ExecuteQuery --> CheckEOF{"记录集未结束?"}
CheckEOF --> |是| InsertListItem["插入列表项"]
InsertListItem --> SetItemText["设置列表项文本"]
SetItemText --> GenerateHandle["生成测区句柄"]
GenerateHandle --> SetItemData["设置列表项数据"]
SetItemData --> MoveNext["移动到下一条记录"]
MoveNext --> CheckEOF
CheckEOF --> |否| CloseRecordset["关闭记录集"]
CloseRecordset --> ReturnTrue["返回true"]
ReturnTrue --> End([结束])
```
**Diagram sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L53-L92)
**Section sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L53-L92)
## 测区类型(TZtype)枚举值及业务含义
测区类型(TZtype)是一个重要的枚举值,用于标识测区的业务类型。根据代码分析,TZtype的取值及其业务含义如下:
- **TZtype=0或1**: 表示"1D VES | 2D ERI"类型,即一维垂直电测深或二维电阻率成像。这两种类型在系统中被视为同一类别进行处理。
- **TZtype=2**: 表示"3D ERT"类型,即三维电阻率层析成像,适用于需要三维空间数据采集的场景。
- **TZtype=3**: 表示"DefaultTestZone"类型,即默认测区。这是一个特殊的测区类型,每个项目创建时都会自动创建一个默认测区。
默认测区(type=3)具有特殊处理逻辑。在创建项目时,系统会自动调用InsertDefaultTzToProject方法为新项目创建一个默认测区。这个默认测区的名称固定为"DefaultTestZone",描述和位置均为"None"。在设备同步过程中,系统会对TZtype=3进行强制检查,如果发现类型不匹配会抛出错误。
```mermaid
classDiagram
class CTestingZone {
+ShowDetailInfo(CListCtrl&)
+CTestingZone(DWORD, _ConnectionPtr&)
+~CTestingZone()
-m_dwID DWORD
-m_pConnection _ConnectionPtr
-m_szTZname CString
-m_szCDate CString
-m_szDesc CString
-m_szLocation CString
-m_szCN CString
-m_szTZtype CString
}
CTestingZone --> "1" CListCtrl : "填充"
```
**Diagram sources**
- [TestingZone.cpp](file://cpp/ProblemZone/TestingZone.cpp#L62-L73)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L319-L341)
**Section sources**
- [TestingZone.cpp](file://cpp/ProblemZone/TestingZone.cpp#L62-L73)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L319-L341)
## 测区配置数据持久化机制
测区配置数据在设备端通过testzone.xml文件进行持久化存储。该文件的生成遵循特定的规则,并具有明确的元素结构。
testzone.xml文件的生成规则如下:当测区数据需要同步到设备时,系统会在本地CACHE目录下创建相应的项目和测区目录结构,然后生成testzone.xml文件。文件路径遵循"\\CACHE\\projects\\{项目CN}\\{测区CN}\\"的层级关系,与项目XML文件保持一致的目录结构。
testzone.xml文件的元素结构包括以下关键字段:
- **type**: 测区类型,对应数据库中的TZtype字段
- **cn**: 测区唯一标识码,对应数据库中的CN字段
- **location**: 测区位置信息
- **desc**: 测区描述信息
- **create_date**: 创建日期
- **testzone_name**: 测区名称
```mermaid
flowchart TD
Start([开始]) --> CreateDirectory["创建本地目录"]
CreateDirectory --> CreateXML["创建XML文档"]
CreateXML --> AddRoot["添加根元素testzone"]
AddRoot --> AddType["添加type元素"]
AddType --> AddLocation["添加location元素"]
AddLocation --> AddDesc["添加desc元素"]
AddDesc --> AddCreateDate["添加create_date元素"]
AddCreateDate --> AddCreateTime["添加create_time元素"]
AddCreateTime --> AddTestDate["添加test_date元素"]
AddTestDate --> AddTestTime["添加test_time元素"]
AddTestTime --> AddCN["添加cn元素"]
AddCN --> AddName["添加testzone_name元素"]
AddName --> Add3DScript["添加testzone_3D_script元素"]
Add3DScript --> AddVess["添加vess元素"]
AddVess --> AddEris["添加eris元素"]
AddEris --> AddErts["添加erts元素"]
AddErts --> AddWels["添加wels元素"]
AddWels --> SaveFile["保存文件"]
SaveFile --> SendToDevice["发送到设备"]
SendToDevice --> UpdateDB["更新数据库同步状态"]
UpdateDB --> End([结束])
```
**Diagram sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L586-L605)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L838-L856)
**Section sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L586-L605)
## 测区创建完整性校验流程
测区创建时的完整性校验流程包括多个步骤,确保数据的完整性和一致性。当用户通过UI界面创建新测区时,系统会执行以下校验流程:
首先,系统会检查测区名称是否为空。如果名称为空,会弹出错误提示"测区名称不能为空",并阻止创建操作。这是最基本的完整性校验,确保每个测区都有一个有效的名称标识。
对于TZtype=3的默认测区,系统有特殊的强制检查机制。在CreateDefaultTzInDev方法中,系统会检查从数据库读取的测区类型是否为3。如果不是,会立即返回错误并显示相应的错误信息。这种强制检查确保了默认测区的特殊性不会被破坏。
```mermaid
sequenceDiagram
participant UI as "用户界面"
participant ProManager as "CProManager"
participant Database as "数据库"
UI->>ProManager : 调用CreateTzInDB
ProManager->>UI : 显示创建对话框
UI->>ProManager : 输入测区信息并确认
ProManager->>ProManager : 验证测区名称是否为空
alt 名称为空
ProManager->>UI : 显示错误提示
ProManager-->>UI : 返回失败
else 名称有效
ProManager->>Database : 查询同名测区是否存在
Database-->>ProManager : 返回查询结果
alt 测区已存在
ProManager->>UI : 显示"测区已存在"提示
ProManager-->>UI : 返回重复错误
else 测区不存在
ProManager->>Database : 插入新测区记录
Database-->>ProManager : 返回插入结果
ProManager->>Database : 查询新测区ID
Database-->>ProManager : 返回测区ID
ProManager-->>UI : 返回成功
end
end
```
**Diagram sources**
- [opcreatetzdlg.cpp](file://cpp/Views/opcreatetzdlg.cpp#L54-L67)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L956-L1009)
**Section sources**
- [opcreatetzdlg.cpp](file://cpp/Views/opcreatetzdlg.cpp#L54-L67)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L956-L1009)
## 测区数据模型字段说明
测区数据模型包含多个关键属性字段,这些字段在UI界面中有相应的展示方式。主要字段包括:
- **ID**: 测区的唯一标识符,数据库主键,用于内部引用和关联
- **名称(TZname)**: 测区的名称,在测区列表中作为第一列显示
- **描述(TZdesc)**: 测区的详细描述信息,在列表中作为描述列显示
- **创建日期(Cdate)**: 测区的创建日期,格式化为"YYYY-MM-DD"显示
- **位置(location)**: 测区的地理位置信息
- **类型(TZtype)**: 测区的业务类型,决定测区的功能和处理方式
- **CN码**: 测区的唯一编码,用于设备同步和数据交换
在UI界面中,这些字段通过CListCtrl控件进行展示。测区列表视图(appdatatzlistview.cpp)定义了列表的列结构,包括测区名称、类型、创建日期和描述等列。每个列表项的数据通过SetItemData方法存储测区句柄,便于后续操作时快速定位对应的测区对象。
```mermaid
erDiagram
PROJECT ||--o{ TESTING_ZONE : "包含"
PROJECT {
int ID PK
string CN UK
string PRname
datetime PRdate
string PRdesc
string location
}
TESTING_ZONE {
int ID PK
int PRID FK
string CN UK
string TZname
int TZtype
datetime Cdate
string TZdesc
string location
}
```
**Diagram sources**
- [TestingZone.h](file://h/TestingZone.h#L24-L29)
- [appdatatzlistview.cpp](file://cpp/Views/appdatatzlistview.cpp#L86-L100)
- [database_modify.xml](file://database_modify.xml#L13-L18)
**Section sources**
- [TestingZone.h](file://h/TestingZone.h#L24-L29)
- [appdatatzlistview.cpp](file://cpp/Views/appdatatzlistview.cpp#L86-L100)
@@ -0,0 +1,289 @@
# 项目生命周期管理
<cite>
**本文档引用的文件**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [ProManager.h](file://h/ProManager.h)
- [opcreateprojectdlg.cpp](file://cpp/Views/opcreateprojectdlg.cpp)
- [opcreateprojectdlg.h](file://h/opcreateprojectdlg.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)
- [Device.h](file://h/Device.h)
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp)
</cite>
## 目录
1. [项目创建流程](#项目创建流程)
2. [项目元数据收集与验证](#项目元数据收集与验证)
3. [项目唯一标识符生成机制](#项目唯一标识符生成机制)
4. [数据库记录插入与默认测区创建](#数据库记录插入与默认测区创建)
5. [项目数据同步到GD10设备](#项目数据同步到gd10设备)
6. [XML缓存文件生成](#xml缓存文件生成)
7. [项目删除操作与级联清理](#项目删除操作与级联清理)
8. [项目状态管理与性能优化](#项目状态管理与性能优化)
## 项目创建流程
项目生命周期管理的核心功能始于项目创建流程,该流程通过`CProManager::CreateProjectInDB`方法实现。此方法首先实例化`COpCreateProjectDlg`对话框,用于收集用户输入的项目元数据。当用户点击确定按钮时,系统会验证输入数据的完整性并执行后续操作。
项目创建流程遵循严格的事务处理机制,确保数据的一致性和完整性。整个流程包括元数据收集、冲突检测、数据库插入和设备同步等多个阶段。在数据库操作层面,系统使用ADODB组件与Access数据库进行交互,通过SQL语句执行数据的增删改查操作。
**Section sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L249-L317)
- [ProManager.h](file://h/ProManager.h#L51-L52)
## 项目元数据收集与验证
项目元数据的收集通过`opCreateProjectDlg`对话框完成,该对话框提供了用户友好的界面来输入项目相关信息。收集的元数据包括项目CN(唯一标识符)、名称、描述、位置、日期、持续时间、工程监督员(PS)、现场管理员(CS)、工程负责人(PM)、品质保证员(QAS)和标准等关键字段。
系统在数据提交前执行严格的验证机制。首先检查工程名称是否为空,如果为空则弹出提示信息要求用户重新输入。同时,系统还会检测工程名称中是否包含特殊字符,若存在特殊字符也会阻止提交并给出相应提示。此外,在将数据写入数据库之前,系统会查询数据库以确保工程名称的唯一性,避免重复创建相同名称的工程。
```mermaid
flowchart TD
Start([开始创建项目]) --> ShowDialog["显示opCreateProjectDlg对话框"]
ShowDialog --> CollectData["收集项目元数据"]
CollectData --> ValidateEmpty["验证必填字段是否为空"]
ValidateEmpty --> |为空| ShowError1["显示错误提示"]
ValidateEmpty --> |不为空| ValidateSpecial["验证特殊字符"]
ValidateSpecial --> |包含特殊字符| ShowError2["显示特殊字符错误"]
ValidateSpecial --> |无特殊字符| CheckDuplicate["检查工程名称重复"]
CheckDuplicate --> |已存在| ShowError3["显示重复名称错误"]
CheckDuplicate --> |不存在| InsertDB["插入数据库记录"]
InsertDB --> CreateDefaultTz["创建默认测区"]
CreateDefaultTz --> End([项目创建完成])
ShowError1 --> End
ShowError2 --> End
ShowError3 --> End
```
**Diagram sources**
- [opcreateprojectdlg.cpp](file://cpp/Views/opcreateprojectdlg.cpp#L79-L114)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L274-L284)
**Section sources**
- [opcreateprojectdlg.cpp](file://cpp/Views/opcreateprojectdlg.cpp#L21-L192)
- [opcreateprojectdlg.h](file://h/opcreateprojectdlg.h#L15-L68)
## 项目唯一标识符生成机制
项目唯一标识符(CN)的生成机制是确保项目数据完整性和可追溯性的关键环节。系统采用`CGUCodeCreator::GenerateGUIDCode()`方法生成全局唯一标识符作为项目CN。该方法通过复杂的算法生成具有高度唯一性的字符串,有效避免了项目标识符冲突的可能性。
`COpCreateProjectDlg`对话框初始化时,系统自动调用`OnProGenCn`方法生成默认的CN值并填充到输入框中。用户可以选择接受系统生成的CN,也可以手动输入自定义的CN。然而,即使用户手动输入CN,系统仍然会在数据库插入前检查其唯一性,确保不会出现重复的CN值。
项目CN不仅是数据库中的主键标识,还在后续的设备同步过程中发挥重要作用。它被用作文件路径的组成部分,确保每个项目在设备上的存储位置具有唯一性。这种设计使得系统能够准确地识别和管理多个项目,为数据同步和检索提供了可靠的基础。
**Section sources**
- [opcreateprojectdlg.cpp](file://cpp/Views/opcreateprojectdlg.cpp#L117-L122)
- [ProManager.h](file://h/ProManager.h#L67)
- [opcreateprojectdlg.h](file://h/opcreateprojectdlg.h#L59)
## 数据库记录插入与默认测区创建
在完成元数据验证后,系统执行数据库记录插入操作。`CProManager::CreateProjectInDB`方法构建SQL插入语句,将收集到的项目元数据写入Access数据库的project表中。插入的字段包括CN、PRname、PRdesc、location、PRdate、duration、PS、CS、PM、QAS和standard等。
数据库插入操作完成后,系统会自动为新创建的项目生成一个默认测区。这一过程由`InsertDefaultTzToProject`方法实现,该方法首先删除该工程下可能存在的旧默认测区,然后插入一个新的默认测区记录。默认测区的CN同样通过`CGUCodeCreator::GenerateGUIDCode()`方法生成,确保其唯一性。
默认测区的创建遵循特定的命名规则和类型定义,其名称固定为"DefaultTestZone",类型值为3。这种设计保证了每个项目都至少包含一个测区,为后续的数据采集和管理提供了基础结构。同时,通过事务性操作确保了项目与默认测区之间的数据一致性。
```mermaid
classDiagram
class CProManager {
+CreateProjectInDB(DWORD& dwID) UINT
+InsertDefaultTzToProject(DWORD dwProjectID) UINT
-m_pConnection _ConnectionPtr
-m_dmsLinkList CLinkList<CDataMngStruct*>
-m_handleProcessor CHandleProcessor
-m_stateProcessor CStateProcessor
-m_guCodeCreator CGUCodeCreator
}
class CGUCodeCreator {
+GenerateGUIDCode() CString
}
class COpCreateProjectDlg {
+OnOK() void
+OnProGenCn() void
-m_edCN CString
-m_edName CString
-m_edPrDesc CString
-m_edLocation CString
-m_edPrDate CTime
-m_edDuration int
-m_edPS CString
-m_edCS CString
-m_edPM CString
-m_edQAS CString
-m_edStandard CString
-m_bCNS bool
-m_guCodeCreator CGUCodeCreator
}
CProManager --> CGUCodeCreator : "使用"
CProManager --> COpCreateProjectDlg : "调用"
COpCreateProjectDlg --> CGUCodeCreator : "使用"
```
**Diagram sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L288-L306)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L319-L341)
**Section sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L249-L341)
## 项目数据同步到GD10设备
项目数据从数据库到GD10设备的同步过程是项目生命周期管理的重要环节。`CProManager::CreateProjectInDev`方法负责将项目数据同步到指定的GD10设备。该过程首先从数据库读取项目详细信息,然后检查设备上是否已存在同名项目,以避免重复创建。
同步过程包含多个关键步骤:首先生成项目XML缓存文件,然后通过`CDevice::SendFile`方法将文件传输到设备。在传输前,系统会创建相应的目录结构,路径格式为"/SD/projects/{项目CN}/"。文件传输成功后,系统更新数据库中的同步状态,记录设备与项目之间的关联关系。
如果文件传输失败,系统会执行回滚操作,删除已在设备上创建的项目,并向用户显示错误提示。这种事务性处理机制确保了数据的一致性,防止出现部分同步导致的数据不一致问题。同时,系统还实现了错误重试机制,提高了同步过程的可靠性。
```mermaid
sequenceDiagram
participant UI as 用户界面
participant ProMgr as CProManager
participant DB as 数据库
participant Device as CDevice
participant FileSys as 文件系统
UI->>ProMgr : 调用CreateProjectInDev
ProMgr->>DB : 查询项目信息
DB-->>ProMgr : 返回项目数据
ProMgr->>DB : 检查设备同步记录
DB-->>ProMgr : 返回检查结果
ProMgr->>FileSys : 创建CACHE目录
FileSys-->>ProMgr : 确认目录创建
ProMgr->>ProMgr : 生成project.xml
ProMgr->>Device : 调用SendFile
Device->>Device : 传输文件到GD10
Device-->>ProMgr : 返回传输结果
alt 传输成功
ProMgr->>DB : 更新同步状态
DB-->>ProMgr : 确认更新
ProMgr-->>UI : 返回成功状态
else 传输失败
ProMgr->>Device : 删除设备上的项目
Device-->>ProMgr : 确认删除
ProMgr-->>UI : 返回失败状态
end
```
**Diagram sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L343-L483)
- [Device.h](file://h/Device.h#L59-L60)
**Section sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L343-L483)
## XML缓存文件生成
XML缓存文件的生成是项目数据同步过程中的关键步骤。系统使用`CMarkup`类创建符合特定格式的XML文件,文件名为"project.xml",存储在本地CACHE目录中。XML文件的结构设计遵循预定义的模式,包含项目的所有元数据信息。
XML文件的根元素为"project",其下包含多个子元素,如project_name、cn、description、location、create_date、create_time、test_date、test_time、duration、PS、CS、PM、QA、standard和testzone_count等。这些元素准确反映了项目在数据库中的属性,确保了数据的一致性。
在生成XML文件时,系统会设置适当的编码格式(ansi)和XML声明。文件内容经过格式化处理,包含适当的换行符,提高了可读性。生成的XML文件不仅用于设备同步,还可作为数据备份和交换的中间格式,增强了系统的灵活性和可维护性。
```mermaid
erDiagram
PROJECT ||--o{ TESTZONE : "包含"
PROJECT {
string CN PK
string PRname
string PRdesc
string location
date PRdate
int duration
string PS
string CS
string PM
string QAS
string standard
}
TESTZONE {
int ID PK
string CN UK
string TZname
int TZtype
date Cdate
string TZdesc
string location
int PRID FK
}
DEVICE ||--o{ DEV_SYN_TD : "关联"
DEVICE {
string DESN PK
string DevName
string ModelNO
string MDate
string HWV
string SWV
string MacAddress
}
DEV_SYN_TD {
int ID PK
string DESN FK
string PrCN FK
string PrName
string TzCN FK
string TzName
boolean IsSyned
}
PROJECT ||--o{ DEV_SYN_TD : "同步到"
TESTZONE ||--o{ DEV_SYN_TD : "同步到"
```
**Diagram sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L402-L425)
- [Project.h](file://h/Project.h#L26-L37)
**Section sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L398-L428)
## 项目删除操作与级联清理
项目删除操作涉及复杂的级联清理策略,以确保数据完整性和系统稳定性。虽然具体的删除方法实现未在提供的代码片段中显示,但从`ProManager.h`头文件中可以推断出系统提供了`DeleteProjectInDB``DeleteProjectInDev`等方法用于删除项目。
项目删除过程需要考虑多个关联实体的清理,包括测区、任务数据以及设备上的同步文件。系统可能采用事务性删除机制,确保所有相关数据被一致地清除。在删除数据库记录的同时,还需要清理设备上的对应文件和目录,如"/SD/projects/{项目CN}/"路径下的所有内容。
级联清理策略可能包括:首先删除与项目关联的所有测区数据,然后删除项目本身;在设备端,先删除测区文件,再删除项目目录。这种分层删除方式可以有效避免因外键约束导致的删除失败。同时,系统可能还实现了删除前的确认机制和备份功能,防止误删重要数据。
**Section sources**
- [ProManager.h](file://h/ProManager.h#L48-L49)
## 项目状态管理与性能优化
项目状态管理通过`m_dmsLinkList`缓存数据管理结构实现性能优化。`CProManager`类中的`m_dmsLinkList`成员变量是一个链表容器,用于缓存已加载的项目和测区数据管理结构。这种缓存机制避免了频繁的数据库查询,显著提高了数据访问性能。
当需要获取特定项目的管理结构时,系统首先检查`m_dmsLinkList`中是否已存在对应的`CDataMngStruct`对象。如果存在则直接返回缓存对象;如果不存在,则从数据库加载数据并创建新的管理结构对象,然后将其添加到链表中以便后续重用。这种设计模式有效减少了数据库访问次数,提升了系统响应速度。
缓存管理还包括适当的清理机制。在`CProManager`析构函数中,系统会遍历并删除链表中的所有对象,释放占用的内存资源。这种资源管理策略确保了系统的稳定运行,防止内存泄漏。同时,通过句柄处理器(`m_handleProcessor`)管理对象的生命周期,实现了高效的内存使用和对象复用。
```mermaid
flowchart TD
A([获取DMS对象]) --> B{"缓存中存在?"}
B --> |是| C[返回缓存对象]
B --> |否| D[从数据库加载数据]
D --> E[创建新的DMS对象]
E --> F[添加到m_dmsLinkList]
F --> G[返回新对象]
C --> H([使用DMS对象])
G --> H
H --> I{"操作完成?"}
I --> |否| H
I --> |是| J[释放资源]
J --> K([结束])
style A fill:#4CAF50,stroke:#388E3C
style C fill:#2196F3,stroke:#1976D2
style D fill:#FF9800,stroke:#F57C00
style E fill:#FF9800,stroke:#F57C00
style F fill:#FF9800,stroke:#F57C00
style G fill:#2196F3,stroke:#1976D2
style H fill:#607D8B,stroke:#455A64
style J fill:#F44336,stroke:#D32F2F
```
**Diagram sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L154-L182)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L39-L51)
**Section sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L154-L182)
@@ -0,0 +1,394 @@
# 项目管理
<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)
- [opcreateprojectdlg.h](file://h/opcreateprojectdlg.h)
- [opcreateprojectdlg.cpp](file://cpp/Views/opcreateprojectdlg.cpp)
- [DataMngStruct.h](file://h/DataMngStruct.h)
- [DevManager.h](file://h/DevManager.h)
- [SptManager.h](file://h/SptManager.h)
- [project.xml](file://CACHE/project.xml)
- [testzone.xml](file://CACHE/testzone.xml)
</cite>
## 目录
1. [项目管理概述](#项目管理概述)
2. [CProManager类架构与实现](#cpromanager类架构与实现)
3. [项目数据模型与持久化](#项目数据模型与持久化)
4. [项目与测区的层级关系](#项目与测区的层级关系)
5. [项目配置同步到设备流程](#项目配置同步到设备流程)
6. [项目管理API使用示例](#项目管理api使用示例)
7. [与其他管理器的集成](#与其他管理器的集成)
8. [多项目环境下的资源管理](#多项目环境下的资源管理)
## 项目管理概述
Geomative Studio的项目管理模块是整个系统的核心组件,负责管理地质探测项目的全生命周期。该模块通过CProManager类实现,提供了项目创建、打开、配置和删除等核心功能。每个项目包含一个或多个测区(TZ),形成清晰的层级结构。项目数据存储在数据库中,并通过XML缓存文件在本地持久化,同时支持与设备的双向同步。本模块与设备管理器、脚本管理器等组件紧密集成,确保了数据的一致性和操作的协同性。
## CProManager类架构与实现
CProManager类是项目管理的核心实现,负责协调项目和测区的创建、查询和删除操作。该类通过数据库连接管理项目数据,并与设备进行通信以实现数据同步。
```mermaid
classDiagram
class CProManager {
+ShowProList(dwDevHandle, proList) bool
+ShowTzList(dwProHandle, tzList) bool
+GetDMS(dwHandle) CDataMngStruct*
+CreateProjectInDB(dwID) UINT
+CreateProjectInDev(dwID, pDev) UINT
+CreateTzInDB(dwID, dwPrID) UINT
+CreateTzInDev(dwID, pDev) UINT
+DeleteProjectInDB(dwID) void
+DeleteProjectInDev(szMac, szPrCN, pDev) UINT
+DeleteTzInDB(dwID) void
+DeleteTzInDev(szPrCN, szTzCN, pDev) UINT
+InsertDefaultTzToProject(dwProjectID) UINT
+CreateDefaultTzInDev(dwProID, pDev) UINT
}
class CDataMngStruct {
+ShowDetailInfo(dmsDetailList) bool
}
class CProject {
+ShowDetailInfo(proDetailList) bool
}
class CTestingZone {
+ShowDetailInfo(tzDetailList) bool
}
CProManager --> CDataMngStruct : "管理"
CDataMngStruct <|-- CProject : "继承"
CDataMngStruct <|-- CTestingZone : "继承"
CProManager --> CLinkList : "m_dmsLinkList"
CProManager --> CHandleProcessor : "m_handleProcessor"
```
**图表来源**
- [ProManager.h](file://h/ProManager.h#L30-L74)
- [Project.h](file://h/Project.h#L16-L38)
- [TestingZone.h](file://h/TestingZone.h#L14-L30)
- [DataMngStruct.h](file://h/DataMngStruct.h#L14-L20)
**本节来源**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L32-L80)
- [ProManager.h](file://h/ProManager.h#L30-L74)
## 项目数据模型与持久化
项目数据模型包含多个关键字段,这些字段在数据库和XML缓存文件中保持一致。项目数据首先存储在数据库的project表中,然后通过XML文件在本地缓存。
### 项目数据模型字段
| 字段名 | 中文名称 | 数据类型 | 描述 |
|-------|--------|--------|------|
| CN | 项目编号 | 字符串 | 项目的唯一标识符,使用GUID生成 |
| PRname | 项目名称 | 字符串 | 项目的名称,用户可读 |
| PRdesc | 项目描述 | 字符串 | 项目的详细描述信息 |
| location | 位置 | 字符串 | 项目实施的地理位置 |
| PRdate | 创建日期 | 日期 | 项目的创建日期 |
| duration | 持续时间 | 字符串 | 项目预计的持续时间 |
| PS | 项目负责人 | 字符串 | 项目的主要负责人 |
| CS | 客户名称 | 字符串 | 项目的客户或委托方 |
| PM | 项目经理 | 字符串 | 项目的管理负责人 |
| QAS | 质量保证 | 字符串 | 质量保证相关人员 |
| standard | 标准 | 字符串 | 项目遵循的技术标准 |
### XML缓存持久化机制
项目数据通过XML文件在CACHE目录下持久化存储。系统使用CMarkup库创建和解析XML文件,确保数据的可读性和可移植性。
```xml
<?xml version="1.0" encoding="ansi"?>
<project>
<project_name>test project</project_name>
<cn>63EFC4AB5B284FC8B1B46F0CEB8F9DA4</cn>
<description />
<location />
<create_date>2016-05-17</create_date>
<create_time>00:00:00</create_time>
<test_date>2020-04-11</test_date>
<test_time>11:53:06</test_time>
<duration>10</duration>
<PS />
<CS />
<PM />
<QA />
<standard />
<testzone_count>0</testzone_count>
<testzones>
<testzone TYPE="3">A9F3D38BDCF84401B8C3050D583BCBEE</testzone>
</testzones>
</project>
```
当创建新项目时,系统会自动生成XML文件并存储在`CACHE\projects\<项目编号>\`目录下。这种持久化机制确保了即使在离线状态下,项目数据也能被访问和管理。
**本节来源**
- [Project.h](file://h/Project.h#L26-L37)
- [project.xml](file://CACHE/project.xml)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L397-L426)
## 项目与测区的层级关系
项目与测区之间存在明确的层级关系,一个项目可以包含多个测区,形成树状结构。这种设计符合地质探测的实际工作流程,允许用户在同一个项目下管理多个不同位置或类型的探测区域。
### 层级结构实现
```mermaid
graph TD
A[项目] --> B[测区1]
A --> C[测区2]
A --> D[测区3]
B --> E[1D VES \| 2D ERI]
C --> F[3D ERT]
D --> G[All Type]
```
在数据模型中,项目(Project)和测区(TestingZone)都继承自CDataMngStruct基类,实现了多态性。CProManager通过m_dmsLinkList链表管理所有项目和测区对象,使用句柄(Handle)机制进行高效访问。
测区类型通过TZtype字段表示:
- 类型1或01D VES | 2D ERI(一维垂直电测深或二维电阻率成像)
- 类型2:3D ERT(三维电阻率断层扫描)
- 类型3:默认测区
每个项目创建时会自动包含一个默认测区,确保项目结构的完整性。用户可以通过GUI界面或API创建额外的测区来满足不同的探测需求。
```mermaid
sequenceDiagram
participant GUI as GUI界面
participant ProManager as CProManager
participant DB as 数据库
participant XML as XML缓存
GUI->>ProManager : 创建项目请求
ProManager->>DB : 在数据库创建项目记录
DB-->>ProManager : 返回项目ID
ProManager->>DB : 为项目插入默认测区
ProManager->>XML : 创建project.xml文件
ProManager->>XML : 创建testzone.xml文件
ProManager-->>GUI : 返回创建结果
```
**图表来源**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L319-L341)
- [TestingZone.cpp](file://cpp/ProblemZone/TestingZone.cpp#L61-L73)
- [testzone.xml](file://CACHE/testzone.xml)
**本节来源**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L319-L341)
- [TestingZone.cpp](file://cpp/ProblemZone/TestingZone.cpp#L61-L73)
- [testzone.xml](file://CACHE/testzone.xml)
## 项目配置同步到设备流程
项目配置同步到设备是项目管理的关键功能,确保了现场设备与工作站的数据一致性。该流程涉及多个步骤,包括数据准备、文件传输和状态更新。
### 同步流程
```mermaid
flowchart TD
A[开始同步] --> B{项目已存在?}
B --> |否| C[在设备中创建项目]
B --> |是| D[跳过创建]
C --> E[生成项目XML文件]
E --> F[创建本地缓存目录]
F --> G[传输文件到设备]
G --> H{传输成功?}
H --> |是| I[更新数据库同步状态]
H --> |否| J[显示错误信息]
J --> K[回滚操作]
I --> L[创建默认测区]
L --> M[生成测区XML文件]
M --> N[传输测区文件到设备]
N --> O{传输成功?}
O --> |是| P[更新数据库同步状态]
O --> |否| Q[显示错误信息]
Q --> R[删除已创建的项目]
P --> S[同步完成]
```
同步流程的具体实现如下:
1. 首先检查项目是否已存在于设备中,避免重复创建
2. 从数据库读取项目配置信息
3. 使用CMarkup库生成project.xml文件
4. 创建本地缓存目录`CACHE\projects\<项目编号>\`
5. 调用设备的SendFile方法将文件传输到设备的/SD/projects/目录
6. 如果传输成功,更新数据库中的同步状态;如果失败,执行回滚操作
此流程确保了数据同步的原子性和一致性,防止了部分同步导致的数据不一致问题。
**图表来源**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L343-L483)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L485-L707)
**本节来源**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L343-L707)
## 项目管理API使用示例
项目管理模块提供了丰富的API,支持通过GUI界面和后台代码进行项目操作。以下是常见的使用示例。
### GUI界面操作
通过GUI界面创建项目的流程:
1. 用户点击"新建项目"按钮
2. 系统弹出COpCreateProjectDlg对话框
3. 用户填写项目信息(名称、描述、位置等)
4. 系统验证项目名称的唯一性
5. 调用CProManager::CreateProjectInDB方法在数据库中创建项目
```cpp
// GUI创建项目的核心代码流程
COpCreateProjectDlg opCreateProDlg;
INT_PTR lRet = opCreateProDlg.DoModal();
if (IDOK == lRet) {
UINT uExecCode = theApp.m_pProManager->CreateProjectInDB(dwID);
if (APP_SUCCESS == uExecCode) {
// 更新UI显示
}
}
```
### 后台代码操作
通过后台代码创建和管理项目的示例:
```mermaid
sequenceDiagram
participant App as 应用程序
participant DataOperator as DataOperator
participant ProManager as CProManager
participant DB as 数据库
App->>DataOperator : CreateProjectInDB(pNavDataView)
DataOperator->>ProManager : CreateProjectInDB(dwID)
ProManager->>DB : 检查项目名称是否存在
DB-->>ProManager : 返回检查结果
ProManager->>DB : 插入项目记录
DB-->>ProManager : 返回项目ID
ProManager->>ProManager : InsertDefaultTzToProject
ProManager-->>DataOperator : 返回执行代码
DataOperator->>DB : 开始事务
DataOperator->>DB : 提交事务
DataOperator-->>App : 返回结果
```
后台操作的关键特点是使用了数据库事务,确保了操作的原子性。如果任何步骤失败,整个事务将被回滚,保持数据的一致性。
**图表来源**
- [opcreateprojectdlg.cpp](file://cpp/Views/opcreateprojectdlg.cpp#L21-L37)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp#L618-L667)
**本节来源**
- [opcreateprojectdlg.h](file://h/opcreateprojectdlg.h#L15-L36)
- [opcreateprojectdlg.cpp](file://cpp/Views/opcreateprojectdlg.cpp#L21-L37)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp#L618-L667)
## 与其他管理器的集成
项目管理器与设备管理器、脚本管理器等组件紧密集成,形成了完整的系统架构。这种集成确保了各模块之间的数据一致性和操作协同性。
### 与设备管理器的集成
项目管理器与设备管理器通过设备句柄和序列号进行通信。当需要将项目同步到设备时,项目管理器会调用设备管理器获取设备对象,然后执行文件传输操作。
```mermaid
classDiagram
class CProManager {
+CreateProjectInDev(dwID, pDev) UINT
+CreateTzInDev(dwID, pDev) UINT
}
class CDevManager {
+GetDevice(dwHandle) CDevice*
+GetDevice(szDevSN) CDevice*
}
class CDevice {
+SendFile(szHostPath, szLocalPath, szFileName) BOOL
+m_szDevSN CString
}
CProManager --> CDevice : "使用"
CDevManager --> CDevice : "管理"
CProManager ..> CDevManager : "依赖"
```
这种设计实现了关注点分离,项目管理器专注于项目数据的管理,而设备管理器负责设备的连接和通信。
### 与脚本管理器的集成
项目管理器与脚本管理器的集成主要体现在测区与脚本的关系上。每个测区可以关联多个探测脚本,这些脚本由脚本管理器管理。
```mermaid
graph TD
A[CProManager] --> |获取| B[CDevManager]
B --> |提供| C[CDevice]
C --> |用于| D[文件传输]
A --> |创建| E[project.xml]
A --> |创建| F[testzone.xml]
E --> |包含| G[项目元数据]
F --> |包含| H[测区元数据]
F --> |引用| I[脚本文件]
I --> |由| J[CSptManager]
J --> |管理| K[脚本生命周期]
```
脚本管理器负责脚本的创建、编辑和删除,而项目管理器确保这些脚本与正确的测区关联。这种分工使得系统更加模块化,易于维护和扩展。
**图表来源**
- [DevManager.h](file://h/DevManager.h#L16-L68)
- [SptManager.h](file://h/SptManager.h#L27-L87)
- [ProManager.h](file://h/ProManager.h#L30-L74)
**本节来源**
- [DevManager.h](file://h/DevManager.h#L16-L68)
- [SptManager.h](file://h/SptManager.h#L27-L87)
## 多项目环境下的资源管理
在多项目环境下,系统需要高效管理内存和文件资源,避免资源泄漏和性能下降。CProManager类通过链表和句柄机制实现了高效的资源管理。
### 内存管理策略
CProManager使用CLinkList模板类管理所有项目和测区对象。每个对象通过唯一句柄访问,实现了对象的延迟加载和缓存机制。
```cpp
// 对象获取的伪代码
CDataMngStruct* CProManager::GetDMS(DWORD dwHandle) {
CDataMngStruct* pDMS = m_dmsLinkList.Get(dwHandle);
if (NULL == pDMS) {
// 按需创建对象
pDMS = new CProject(dwID, m_pConnection);
m_dmsLinkList.Add(dwHandle, pDMS);
}
return pDMS;
}
```
这种策略的优点:
- **延迟加载**:只有在需要时才从数据库加载数据,减少启动时间和内存占用
- **对象缓存**:重复访问同一对象时直接从缓存获取,提高性能
- **内存控制**:通过链表管理对象生命周期,避免内存泄漏
### 资源清理机制
系统在析构时会清理所有管理的对象:
```cpp
CProManager::~CProManager() {
int iDMSIndex = 0;
while (NULL != m_dmsLinkList.Find(iDMSIndex)) {
delete m_dmsLinkList.Find(iDMSIndex);
iDMSIndex++;
}
m_dmsLinkList.DeleteAll();
}
```
此外,系统还提供了DeleteObjInMem方法,允许在运行时显式删除不再需要的对象,进一步优化内存使用。
**本节来源**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L39-L51)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L155-L182)
- [ProManager.h](file://h/ProManager.h#L72-L73)