HalconEditorPreview.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. using System;
  2. using System.Collections.Generic;
  3. using TeamAAS.Vision;
  4. using TeamAAS.FlowEditor.Plugins;
  5. using Plugins.Halcon.Views;
  6. namespace Plugins.Halcon
  7. {
  8. /// <summary>
  9. /// 编辑器内嵌预览的挂接点 + 视觉图层发布桥。
  10. ///
  11. /// 两条显示通路(互不干扰):
  12. /// 1) 图层通路(新):<see cref="Show(TeamAAS.FlowEditor.Plugins.BasePluginModel, object, object, string)"/>
  13. /// 把节点运行结果按「节点 → 图层集」发布到 <see cref="VisionLayerStore"/>,
  14. /// HalconFlowEditorView 的大显示窗按选中节点/图层筛选渲染 —— 类 VisionMaster 的图层体验;
  15. /// 2) 经典通路(兼容保留):<see cref="Current"/> 静态窗体直接推图(主页引擎画面、旧调用方不受影响)。
  16. ///
  17. /// 内存策略:每轮运行开始(<see cref="BeginRunCycle"/>)换新 RunStamp;同名节点再次发布=整体替换,
  18. /// 跨批次发布时由 VisionLayerStore 释放上一批次自有对象(GenImage 副本等),图层永不无限叠加。
  19. /// </summary>
  20. public static class HalconEditorPreview
  21. {
  22. static HalconEditorPreview()
  23. {
  24. // 图层库释放自有对象时走 HALCON 安全释放(吞异常)
  25. VisionLayerStore.Disposer = obj =>
  26. {
  27. var h = obj as HalconDotNet.HObject;
  28. if (h != null) { HalconRuntime.Dispose(h); return; }
  29. var d = obj as IDisposable;
  30. if (d != null) { try { d.Dispose(); } catch { } }
  31. };
  32. }
  33. /// <summary>当前 HALCON 流程编辑器内嵌的预览窗体(无编辑器打开时为 null)——经典通路。</summary>
  34. public static HalconWindow Current { get; set; }
  35. private static string _runStamp = "0";
  36. /// <summary>当前运行批次号(每轮容器运行开始时更新)。</summary>
  37. public static string RunStamp => _runStamp;
  38. private static long _runSeq = 0;
  39. /// <summary>
  40. /// 一轮运行开始:更新 RunStamp 并清掉上一轮遗留图层(防跨轮叠加)。
  41. /// 由 HalconFlowPlugin.PluginRun 在执行子流程前调用。
  42. /// </summary>
  43. public static void BeginRunCycle()
  44. {
  45. _runSeq++;
  46. _runStamp = _runSeq.ToString();
  47. VisionLayerStore.Instance.ClearAll();
  48. }
  49. /// <summary>
  50. /// 【图层通路】节点运行结果发布:写 VisionLayerStore(驱动编辑器大显示窗/图层筛选),
  51. /// 同时保持经典通路(Current 窗体直接推图)行为不变。
  52. /// 后台线程调用安全(内部切 UI 线程);无消费方时零开销。
  53. /// </summary>
  54. /// <param name="model">节点模型(取 FlowId/NodeName/NodeName 定位图层归属)</param>
  55. /// <param name="image">底图(HObject/GenImage),null=只叠加</param>
  56. /// <param name="overlay">叠加对象(区域/XLD),null=无</param>
  57. /// <param name="color">叠加颜色(如 "green"),null 用默认</param>
  58. public static void Show(BasePluginModel model, object image, object overlay = null, string color = null)
  59. {
  60. string flowId = model?.FlowId;
  61. string nodeName = model?.NodeName;
  62. bool hasContext = !string.IsNullOrEmpty(flowId) && !string.IsNullOrEmpty(nodeName);
  63. // 1) 图层发布(有节点上下文才发布)
  64. if (hasContext)
  65. {
  66. var args = new LayerPublishArgs
  67. {
  68. FlowId = flowId,
  69. NodeName = nodeName,
  70. RunStamp = _runStamp,
  71. };
  72. if (image != null)
  73. args.Layers.Add(new LayerItem("图像", LayerKind.Image, image,
  74. owned: !(image is HalconDotNet.HObject)));
  75. if (overlay != null)
  76. args.Layers.Add(new LayerItem("区域", LayerKind.Region, overlay,
  77. owned: !(overlay is HalconDotNet.HObject), color: color ?? "red"));
  78. if (args.Layers.Count > 0)
  79. VisionLayerStore.Instance.Publish(args);
  80. }
  81. // 2) 经典通路:编辑器内嵌窗体直接推图(行为不变)
  82. Show(image, overlay);
  83. }
  84. /// <summary>
  85. /// 【经典通路】把结果推到编辑器内嵌预览窗体(若已打开)。
  86. /// image 可为 null(只更新叠加区域、保留底图,供只产出区域的节点用)。
  87. /// 在后台线程调用也安全(内部切 UI 线程);无预览窗体时静默跳过(生产运行零开销)。
  88. /// </summary>
  89. public static void Show(object image, object overlay = null)
  90. {
  91. var w = Current;
  92. if (w == null) return;
  93. try
  94. {
  95. System.Windows.Application.Current?.Dispatcher.Invoke(() => w.RefreshImage(image, overlay));
  96. }
  97. catch { }
  98. }
  99. }
  100. }