# 自定义脚本 **本文档中引用的文件** - [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) ## 目录 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 { <> } 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在复杂勘探任务中的优势。