Solution.cs(433行,全局大脑):
- 单例模式,
Ins可被CreateSolution()覆盖重建 ProjectList管理 N 个流程,End流程永远插在末尾,新建流程自动 ID 分配- 四组运行控制:全局
StartRun/ExecuteOnce/StopRun+ 单流程StartRun/ExecuteOnce/StopRun(id),StopRun会先启动 End 流程作为收尾钩子 SetIsEnable()运行/空闲状态切换时禁用/恢复所有 UI 按钮QueueDic+QueueSignDic全局队列(跨 Project DataIn/DataOut 共享)LoadCommunacation/UpdataCommunacation通讯设备的序列化/恢复桥梁
SolutionInfo.cs(765行,数据结构库):
- 20+ 个几何/标定/测量数据结构,全部
[Serializable] ROIBase抽象基类(genRegion/genXLD/getTuple三接口)- 核心类型:
Line_Info(自动计算中点/方向)、Circle_Info(弧支持)、Coord_Info(项目中使用最频繁的 X/Y/Phi/Score)、Cal_Info(17 字段标定信息)、RPoint(支持-运算符和GetDistance属性) - 完整生命周期流程图:从反序列化恢复 → 运行中 → 保存序列化
Solution.cs & SolutionInfo.cs 完整解析
文件:
Services\Solution.cs(433行) +Services\SolutionInfo.cs(765行)
角色: Solution = 全局大脑 (流程管理/单例/运行控制) | SolutionInfo = 数据结构库 (几何类型/标定信息)
总计: ~1200行
一、Solution.cs — 全局大脑
1.1 架构定位
Solution (单例) │ ┌───────────┼───────────┐ ▼ ▼ ▼ ProjectList QueueDic SysVar (N个流程) (数据队列) (全局变量) │ ┌────┼────┐ ▼ ▼ ▼ Home 主流程 End1.2 单例模式
privatestaticSolution_Instance=null;publicstaticSolutionIns{get{if(_Instance==null)_Instance=newSolution();return_Instance;}set{_Instance=value;}// ← 可被外部覆盖!}set的意义:CreateSolution()会执行Ins = new Solution()覆盖旧实例 — 这是"新建方案"的实现方式。
1.3 属性全景
流程相关
| 属性 | 类型 | 说明 |
|---|---|---|
ProjectList | List<Project> | 所有流程/方法/文件夹 |
CurrentProject | Project | 当前激活的流程 |
CurrentProjectID | int | 当前流程ID |
全局数据
| 属性 | 类型 | 说明 |
|---|---|---|
QueueDic | Dictionary<string, DataOut> | DataIn/DataOut 共享队列 |
QueueSignDic | Dictionary<string, AutoResetEvent> | 队列信号量 |
SysVar | ObservableCollection<VarModel> | 全局变量 (所有流程共享) |
UI/配置
| 属性 | 类型 | 说明 |
|---|---|---|
UIDesignText | string | 自定义UI布局XAML |
IsUseUIDesign | bool | 是否启用自定义UI |
QuickMode | bool | 快速模式 (跳过UI刷新和延时) |
ViewMode | eViewMode | 画布显示模式 |
eCommunacations | List<ECommunacation> | 通讯设备列表 (序列化持久化) |
1.4 核心方法详解
SetIsEnable() — UI按钮状态切换
publicvoidSetIsEnable(){boolrunning=GetStates();// 检查是否有任何流程在运行if(running){// ★ 运行中: 禁用所有编辑操作, 开启停止/继续按钮IsEnableControl.Ins.Stop=true;IsEnableControl.Ins.RunCycle=false;IsEnableControl.Ins.NewSolution=false;// ...ProcessView.Ins.btnRunOnce.ToolTip="继续运行(F5)";}else{// ★ 空闲中: 恢复所有按钮IsEnableControl.Ins.Stop=false;IsEnableControl.Ins.RunOnce=true;IsEnableControl.Ins.NewSolution=true;// ...ProcessView.Ins.btnRunOnce.ToolTip="当前项目单次执行";}}调用时机: 每次Project.ThreadStatus变化时触发 (set { _ThreadStatus = value; Solution.Ins.SetIsEnable(); })
CreateSolution() — 新建方案
publicvoidCreateSolution(){// ① 确认弹窗MessageView.Ins.MessageBoxShow("创建新的解决方案会覆盖掉当前已有的解决方案...",...);// ② 清空 + 重建Ins=newSolution();// ③ 创建三个默认流程: Home, 主流程, EndIns.CreateProject(eProjectType.Process);// → HomeIns.CreateProject(eProjectType.Process);// → 主流程Ins.CreateProject(eProjectType.Process);// → EndIns.ProjectList[0].ProjectInfo.ProcessName="Home";Ins.ProjectList[1].ProjectInfo.ProcessName="主流程";Ins.ProjectList[2].ProjectInfo.ProcessName="End";}CreateProject() — 创建流程 (自动ID分配)
publicintCreateProject(eProjectTypeprojectType,intparentId=0){Projectproject=newProject();// ← 构造函数启动后台线程!// ① 自动分配不重复的ID (轮询最小未被占用的)intid=0;do{flag=true;foreach(ProjectprjinProjectList)if(prj.ProjectInfo.ProjectID==id){id++;flag=false;break;}}while(!flag);project.ProjectInfo.ProjectID=id;project.ProjectInfo.ProcessName=$"流程{id}";// 默认名// ② Method 类型插入到父级后面, 其他类型插入到倒数第二个 (End之前)if(projectType==eProjectType.Method)ProjectList.Insert(parentIndex+1,project);elseProjectList.Insert(ProjectList.Count-1,project);// End 永远在最后CurrentProject=project;returnid;}关键设计: 任何新建流程都插入到End之前 —End流程永远在列表末尾, 是停止运行的专用流程。
运行控制 — 四组方法
// ===== 全局运行 (全部"主动执行"的流程) =====StartRun()// 循环运行 (RunCycle)ExecuteOnce()// 单次运行 (RunOnce)ExecuteOnceHome()// 仅运行 Home 流程StopRun()// 停止: 运行 End 流程 + 其他流程 Stop()// ===== 单流程运行 (指定 projectID) =====StartRun(intprojectID)// 循环ExecuteOnce(intprojectID)// 单次StopRun(intprojectID)// 停止全局 StopRun 的特殊处理:
publicvoidStopRun(){ProjectList.ForEach(item=>{if(item.ProjectInfo.ProcessName=="End"){item.RunMode=eRunMode.RunOnce;item.Start();// ★ 运行 End 流程 (做清理/收尾工作)}else{item.Stop();}});}End流程不停止, 反而被启动 — 这是一个"收尾钩子"设计: 在停止所有流程前运行一次 End 流程。
LoadCommunacation / UpdataCommunacation — 通讯设备持久化
// 反序列化后调用: 把持久化的设备列表恢复到全局字典并连接publicvoidLoadCommunacation(){foreach(varitemineCommunacations){item.IsConnected=false;// 反序列化后状态均为断开item.IsHasObjectConnected=false;}EComManageer.setEcomList(eCommunacations);// → 恢复字典 + 逐个 Connect()}// 序列化前调用: 把全局字典的最新状态写入持久化列表publicvoidUpdataCommunacation(){eCommunacations=EComManageer.GetEcomList();}二、SolutionInfo.cs — 几何数据结构库
2.1 文件定位
这是一个纯数据结构文件— 没有方法逻辑, 全部是class/struct定义。物理上放在Services/SolutionInfo.cs, 命名空间也是JGTechVision.Services, 但逻辑上独立于 Solution。
2.2 类/结构体全景
ROIBase (抽象基类) ├── Line_Info 直线信息 (起点/终点/法向量/方向) ├── Circle_Info 圆信息 (圆心/半径/起止角度) ├── Ellipse_Info 椭圆信息 (中心/Phi/两个半径) ├── Rect_Info 矩形信息 (左上+右下角) ├── Rect2_Info 旋转矩形 (中心/角度/两半边长) ├── DrawRoi_Info 自定义形状 │ ├── Coord_Info 十字坐标 (X/Y/Phi/Score) ├── Cal_Info 标定信息 (17个字段) ├── Meas_Info 测量信息 (长度/宽度/阈值/间隔) ├── NPoint 九点信息 (索引/像素XY/机械XY) ├── RectRoiInfo 矩形阵列返回信息 ├── Point3DF 3D点 (X/Y/Z) ├── Plane_Info 平面信息 ├── TagVector 向量 ├── PtoP_Info 点到点信息 ├── Text_Info 文本信息 ├── Rtn_Info 返回信息 ├── Set_Info 显示设置信息 ├── Luma_Info 亮度信息 ├── Save_Info 保存信息 ├── Char_Info 运算信息 └── RPoint 机器人点位 (支持 - 运算符)2.3 核心类型详解
ROIBase — 几何抽象基类
[Serializable]publicabstractclassROIBase{publicstringsColor{get;set;}="cyan";publicabstractHRegiongenRegion();// 生成 Halcon RegionpublicabstractHXLDContgenXLD();// 生成 Halcon XLD 轮廓publicabstractHTuplegetTuple();// 序列化为 Halcon 元组}所有几何类型继承它, 统一了"区域→轮廓→序列化"三个接口。
Line_Info — 直线信息
publicclassLine_Info:ROIBase,ICloneable{publicdoubleStartX,StartY;// 起点publicdoubleEndX,EndY;// 终点publicdoubleMidX,MidY;// 中点 (构造函数自动计算)publicdoublePhi;// 方向角 (构造函数自动计算)publicdoubleNx,Ny;// 法向量publicdoubleDist;// 到原点的距离}构造函数中的自动计算:Phi = HMisc.AngleLx(StartY, StartX, EndY, EndX)+MidY = (StartY+EndY)/2— 减少外部冗余代码。
Circle_Info — 圆信息
publicclassCircle_Info:ROIBase,ICloneable{publicdoubleCenterY,CenterX,Radius;publicdoubleStartPhi=0.0,EndPhi=Math.PI*2;// 弧的起止角度publicstringPointOrder="positive";// 点顺序}Coord_Info — 十字坐标
publicstructCoord_Info{publicboolStatus;publicdoubleY,X,Phi,Score;// 注意: 存储顺序是 Y, X (Halcon惯例 row→col)}这个 struct 在整个项目中大量使用 — 模板匹配、坐标补正、测量结果都依赖它。
Cal_Info — 标定信息 (17字段)
publicstructCal_Info{publicdoubleParallelX,ParallelY;// 平移publicdoublePixelX,PixelY;// 像素当量publicdoubleRotationAngle;// 旋转角度publicdoubleTiltAngle;// 倾斜角度publicdoubleRMS;// 均方根误差publicdoubleRrotationCenterX,Y;// 旋转中心publicdoubleRotateX_Robot,Y_Robot;// 旋转中心机械坐标publicboolRotatingEnabled;// 旋转启用publicboolSameDirection;// 方向一致publicboolCameraFix;// 相机固定/移动publicdoubleMarkX,MarkY;// Mark点publicdoubleBaselineX,Y,Angel;// 基准坐标/角度}RPoint — 机器人点位 (支持运算符)
publicclassRPoint{publicdoubleX,Y,R;// ★ 支持减法运算符publicstaticRPointoperator-(RPointp1,RPointp2){returnnewRPoint(p1.X-p2.X,p1.Y-p2.Y,p1.R-p2.R);}// ★ 属性计算距离publicdoubleGetDistance=>Math.Sqrt(X*X+Y*Y);}三、Solution 完整生命周期
启动 │ ▼ 反序列化 Solution 对象 │ ├→ Solution.Ins = 反序列化结果 (覆盖单例) ├→ LoadCommunacation() │ └→ EComManageer.setEcomList(eCommunacations) │ └→ 每个设备 Connect() │ ├→ ProjectList 被恢复 │ └→ 每个 Project 构造 → 启动后台线程 → WaitOne 阻塞 │ └→ UI 就绪, 显示 ProjectList ════════ 运行中 ════════ 用户点击"连续运行" │ ▼ Solution.StartRun() ├→ 遍历 ProjectList (排除 Home/End) ├→ RunMode = RunCycle └→ item.Start() → ThreadStatus=true → Set() 用户点击"停止" │ ▼ Solution.StopRun() ├→ End 流程 → Start() (收尾钩子) └→ 其余流程 → Stop() → ThreadStatus=false ════════ 保存 ════════ 用户点击"保存" │ ▼ Solution.UpdataCommunacation() └→ eCommunacations = EComManageer.GetEcomList() 序列化 Solution ├→ ProjectList (含 ModuleList, OutputMap...) ├→ eCommunacations ├→ SysVar └→ UIDesignText文档说明: 基于 Solution.cs (433行) + SolutionInfo.cs (765行) 源码静态分析生成。Solution 是全局单例, 序列化时持久化流程列表、通讯设备和全局变量。SolutionInfo 定义 20+ 几何/标定数据结构, 全部实现
[Serializable]。当前版本 2026-06-10。