合并修改
This commit is contained in:
399
DH.Commons/Base/CameraBase.cs
Normal file
399
DH.Commons/Base/CameraBase.cs
Normal file
@ -0,0 +1,399 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing.Imaging;
|
||||
using AntdUI;
|
||||
using DH.Commons.Enums;
|
||||
using DVPCameraType;
|
||||
using HalconDotNet;
|
||||
using OpenCvSharp;
|
||||
|
||||
namespace DH.Commons.Base
|
||||
{
|
||||
public class MatSet
|
||||
{
|
||||
public DateTime ImageTime { get; set; } = DateTime.Now;
|
||||
|
||||
private string id = "";
|
||||
public string Id
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
id = ImageTime.ToString("HHmmssfff");
|
||||
}
|
||||
return id;
|
||||
}
|
||||
set
|
||||
{
|
||||
id = value;
|
||||
}
|
||||
}
|
||||
public string CameraId { get; set; }
|
||||
public Mat _mat { get; set; } = null;
|
||||
|
||||
public ImageFormat _imageFormat { get; set; } = ImageFormat.Jpeg;
|
||||
public virtual void Dispose()
|
||||
{
|
||||
_mat?.Dispose();
|
||||
_mat = null;
|
||||
|
||||
}
|
||||
}
|
||||
public class CameraBase : NotifyProperty
|
||||
{
|
||||
|
||||
// public LoggerHelper LoggerHelper { get; set; } = new LoggerHelper();
|
||||
|
||||
// 私有字段 + 带通知的属性(与DetectionLabel风格一致)
|
||||
private bool _isEnabled = false;
|
||||
private bool _isallPicEnabled = true;//默认全画幅
|
||||
private bool _isRGBEnabled = true;//默认彩色
|
||||
private bool _isContinueMode = false;
|
||||
private bool _isSavePicEnabled = false;
|
||||
private bool _isZoomCamera = false;
|
||||
private string _imageSaveDirectory;
|
||||
private EnumCamType _CamType;
|
||||
private dvpStreamFormat _dvpstreamFormat = dvpStreamFormat.S_RGB24;
|
||||
private ImageFormat _imageFormat = ImageFormat.Jpeg;
|
||||
private bool _isHardwareTrigger = true;
|
||||
private string _serialNumber = string.Empty;
|
||||
private string _cameraName = string.Empty;
|
||||
private string _cameraIP = string.Empty;
|
||||
private string _computerIP = string.Empty;
|
||||
private bool _isDirectHardwareTrigger = false;
|
||||
private float _gain =6;
|
||||
private int _rotateImage = 0;
|
||||
private float _exposure = 200;
|
||||
private float _triggerDelay = 0;
|
||||
private decimal _roiX = 0;
|
||||
private decimal _roiY = 0;
|
||||
private decimal _roiW = 2448;
|
||||
private decimal _roiH = 2048;
|
||||
private int _lineDebouncerTime = 0;
|
||||
|
||||
public volatile int SnapshotCount = 0;
|
||||
|
||||
[Category("相机设置")]
|
||||
[DisplayName("图像格式")]
|
||||
[Description("相机采集图像格式")]
|
||||
public dvpStreamFormat DvpImageFormat
|
||||
{
|
||||
get => _dvpstreamFormat;
|
||||
set
|
||||
{
|
||||
if (_dvpstreamFormat == value) return;
|
||||
_dvpstreamFormat = value;
|
||||
OnPropertyChanged(nameof(DvpImageFormat));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("采图模式")]
|
||||
[DisplayName("连续模式")]
|
||||
[Description("是否连续模式。true:连续模式采图;false:触发模式采图")]
|
||||
public bool IsContinueMode
|
||||
{
|
||||
get => _isContinueMode;
|
||||
set
|
||||
{
|
||||
if (_isContinueMode == value) return;
|
||||
_isContinueMode = value;
|
||||
OnPropertyChanged(nameof(IsContinueMode));
|
||||
}
|
||||
}
|
||||
public bool IsZoomCamera
|
||||
{
|
||||
get => _isZoomCamera;
|
||||
set
|
||||
{
|
||||
if (_isZoomCamera == value) return;
|
||||
_isZoomCamera = value;
|
||||
OnPropertyChanged(nameof(IsZoomCamera));
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool IsEnabled
|
||||
{
|
||||
get => _isEnabled;
|
||||
set
|
||||
{
|
||||
if (_isEnabled == value) return;
|
||||
_isEnabled = value;
|
||||
OnPropertyChanged(nameof(IsEnabled));
|
||||
}
|
||||
}
|
||||
public virtual bool IsAllPicEnabled
|
||||
{
|
||||
get => _isallPicEnabled;
|
||||
set
|
||||
{
|
||||
if (_isallPicEnabled == value) return;
|
||||
_isallPicEnabled = value;
|
||||
OnPropertyChanged(nameof(IsAllPicEnabled));
|
||||
}
|
||||
}
|
||||
public virtual bool IsSavePicEnabled
|
||||
{
|
||||
get => _isSavePicEnabled;
|
||||
set
|
||||
{
|
||||
if (_isSavePicEnabled == value) return;
|
||||
_isSavePicEnabled = value;
|
||||
OnPropertyChanged(nameof(IsSavePicEnabled));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("图片保存")]
|
||||
[DisplayName("图片保存文件夹")]
|
||||
[Description("图片保存文件夹")]
|
||||
public virtual string ImageSaveDirectory
|
||||
{
|
||||
get => _imageSaveDirectory;
|
||||
set
|
||||
{
|
||||
if (_imageSaveDirectory == value) return;
|
||||
_imageSaveDirectory = value;
|
||||
OnPropertyChanged(nameof(ImageSaveDirectory));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("图片保存")]
|
||||
[DisplayName("图片保存格式")]
|
||||
[Description("图片保存格式")]
|
||||
public ImageFormat ImageFormat
|
||||
{
|
||||
get => _imageFormat;
|
||||
set
|
||||
{
|
||||
if (_imageFormat == value) return;
|
||||
_imageFormat = value;
|
||||
OnPropertyChanged(nameof(ImageFormat));
|
||||
}
|
||||
}
|
||||
[Category("设备配置")]
|
||||
[DisplayName("相机类型")]
|
||||
[Description("相机类型")]
|
||||
public EnumCamType CamType
|
||||
{
|
||||
get => _CamType;
|
||||
set
|
||||
{
|
||||
if (_CamType == value) return;
|
||||
_CamType = value;
|
||||
OnPropertyChanged(nameof(CamType));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("采图模式")]
|
||||
[DisplayName("硬触发")]
|
||||
[Description("是否硬触发模式。true:硬触发;false:软触发")]
|
||||
public bool IsHardwareTrigger
|
||||
{
|
||||
get => _isHardwareTrigger;
|
||||
set
|
||||
{
|
||||
if (_isHardwareTrigger == value) return;
|
||||
_isHardwareTrigger = value;
|
||||
OnPropertyChanged(nameof(IsHardwareTrigger));
|
||||
}
|
||||
}
|
||||
|
||||
public string SerialNumber
|
||||
{
|
||||
get => _serialNumber;
|
||||
set
|
||||
{
|
||||
if (_serialNumber == value) return;
|
||||
_serialNumber = value;
|
||||
OnPropertyChanged(nameof(SerialNumber));
|
||||
}
|
||||
}
|
||||
|
||||
public string CameraName
|
||||
{
|
||||
get => _cameraName;
|
||||
set
|
||||
{
|
||||
if (_cameraName == value) return;
|
||||
_cameraName = value;
|
||||
OnPropertyChanged(nameof(CameraName));
|
||||
}
|
||||
}
|
||||
|
||||
public string CameraIP
|
||||
{
|
||||
get => _cameraIP;
|
||||
set
|
||||
{
|
||||
if (_cameraIP == value) return;
|
||||
_cameraIP = value;
|
||||
OnPropertyChanged(nameof(CameraIP));
|
||||
}
|
||||
}
|
||||
|
||||
public string ComputerIP
|
||||
{
|
||||
get => _computerIP;
|
||||
set
|
||||
{
|
||||
if (_computerIP == value) return;
|
||||
_computerIP = value;
|
||||
OnPropertyChanged(nameof(ComputerIP));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("采图模式")]
|
||||
[DisplayName("是否传感器直接硬触发")]
|
||||
[Description("是否传感器直接硬触发。true:传感器硬触发,不通过软件触发;false:通过软件触发IO 的硬触发模式")]
|
||||
public bool IsDirectHardwareTrigger
|
||||
{
|
||||
get => _isDirectHardwareTrigger;
|
||||
set
|
||||
{
|
||||
if (_isDirectHardwareTrigger == value) return;
|
||||
_isDirectHardwareTrigger = value;
|
||||
OnPropertyChanged(nameof(IsDirectHardwareTrigger));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("相机设置")]
|
||||
[DisplayName("增益")]
|
||||
[Description("Gain:增益,-1:不设置,不同型号相机的增益,请参考mvs")]
|
||||
public float Gain
|
||||
{
|
||||
get => _gain;
|
||||
set
|
||||
{
|
||||
if (_gain.Equals(value)) return;
|
||||
_gain = value;
|
||||
OnPropertyChanged(nameof(Gain));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("图像旋转")]
|
||||
[DisplayName("默认旋转")]
|
||||
[Description("默认旋转,相机开启后默认不旋转")]
|
||||
public virtual int RotateImage
|
||||
{
|
||||
get => _rotateImage;
|
||||
set
|
||||
{
|
||||
if (_rotateImage.Equals(value)) return;
|
||||
_rotateImage = value;
|
||||
OnPropertyChanged(nameof(RotateImage));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("取像配置")]
|
||||
[DisplayName("曝光")]
|
||||
[Description("曝光")]
|
||||
public virtual float Exposure
|
||||
{
|
||||
get => _exposure;
|
||||
set
|
||||
{
|
||||
if (_exposure.Equals(value)) return;
|
||||
_exposure = value;
|
||||
OnPropertyChanged(nameof(Exposure));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("相机设置")]
|
||||
[DisplayName("硬触发后的延迟")]
|
||||
[Description("TriggerDelay:硬触发后的延迟,单位:us 微秒")]
|
||||
public float TriggerDelay
|
||||
{
|
||||
get => _triggerDelay;
|
||||
set
|
||||
{
|
||||
if (_triggerDelay.Equals(value)) return;
|
||||
_triggerDelay = value;
|
||||
OnPropertyChanged(nameof(TriggerDelay));
|
||||
}
|
||||
}
|
||||
|
||||
public decimal ROIX
|
||||
{
|
||||
get => _roiX;
|
||||
set
|
||||
{
|
||||
if (_roiX == value) return;
|
||||
_roiX = value;
|
||||
OnPropertyChanged(nameof(ROIX));
|
||||
}
|
||||
}
|
||||
|
||||
public decimal ROIY
|
||||
{
|
||||
get => _roiY;
|
||||
set
|
||||
{
|
||||
if (_roiY == value) return;
|
||||
_roiY = value;
|
||||
OnPropertyChanged(nameof(ROIY));
|
||||
}
|
||||
}
|
||||
|
||||
public decimal ROIW
|
||||
{
|
||||
get => _roiW;
|
||||
set
|
||||
{
|
||||
if (_roiW == value) return;
|
||||
_roiW = value;
|
||||
OnPropertyChanged(nameof(ROIW));
|
||||
}
|
||||
}
|
||||
|
||||
public decimal ROIH
|
||||
{
|
||||
get => _roiH;
|
||||
set
|
||||
{
|
||||
if (_roiH == value) return;
|
||||
_roiH = value;
|
||||
OnPropertyChanged(nameof(ROIH));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("相机设置")]
|
||||
[DisplayName("滤波时间")]
|
||||
[Description("LineDebouncerTime:I/O去抖时间 单位:us")]
|
||||
public int LineDebouncerTime
|
||||
{
|
||||
get => _lineDebouncerTime;
|
||||
set
|
||||
{
|
||||
if (_lineDebouncerTime == value) return;
|
||||
_lineDebouncerTime = value;
|
||||
OnPropertyChanged(nameof(LineDebouncerTime));
|
||||
}
|
||||
}
|
||||
|
||||
// 其他方法保持原有逻辑
|
||||
public MatSet CopyImageSet(MatSet srcSet)
|
||||
{
|
||||
MatSet imageSet = new MatSet
|
||||
{
|
||||
Id = srcSet.Id,
|
||||
_mat = srcSet._mat.Clone(),
|
||||
// ImageSaveOption = srcSet.ImageSaveOption.Copy(),
|
||||
ImageTime = srcSet.ImageTime
|
||||
};
|
||||
return imageSet;
|
||||
}
|
||||
public Action<DateTime, CameraBase, MatSet> OnHImageOutput { get; set; }
|
||||
|
||||
public virtual bool CameraConnect() { return false; }
|
||||
|
||||
public virtual bool CameraDisConnect() { return false; }
|
||||
|
||||
public virtual void SetExposure(int exposureTime, string cameraName) { }
|
||||
|
||||
public virtual void SetGain(int gain, string cameraName) { }
|
||||
|
||||
internal virtual void SetAcquisitionMode(int mode) { }
|
||||
|
||||
internal virtual void SetAcqRegion(int offsetV, int offsetH, int imageH, int imageW, string cameraName) { }
|
||||
}
|
||||
}
|
@ -9,27 +9,14 @@ using AntdUI;
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
using static DH.Commons.Enums.EnumHelper;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json.Serialization;
|
||||
using DH.Commons.Enums;
|
||||
using System.Drawing.Imaging;
|
||||
|
||||
|
||||
namespace DH.Commons.Enums
|
||||
namespace DH.Commons.Base
|
||||
{
|
||||
public enum MLModelType
|
||||
{
|
||||
[Description("图像分类")]
|
||||
ImageClassification = 1,
|
||||
[Description("目标检测")]
|
||||
ObjectDetection = 2,
|
||||
//[Description("图像分割")]
|
||||
//ImageSegmentation = 3
|
||||
[Description("语义分割")]
|
||||
SemanticSegmentation = 3,
|
||||
[Description("实例分割")]
|
||||
InstanceSegmentation = 4,
|
||||
[Description("目标检测GPU")]
|
||||
ObjectGPUDetection = 5
|
||||
}
|
||||
public class ModelLabel
|
||||
|
||||
public class ModelLabel
|
||||
{
|
||||
public string LabelId { get; set; }
|
||||
|
||||
@ -45,7 +32,7 @@ namespace DH.Commons.Enums
|
||||
[Description("模型识别的标签名称")]
|
||||
public string LabelName { get; set; }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//[Category("模型配置")]
|
||||
@ -74,28 +61,28 @@ namespace DH.Commons.Enums
|
||||
//public int ImageResizeCount;
|
||||
public bool IsCLDetection;
|
||||
public int ProCount;
|
||||
public string in_node_name;
|
||||
public string in_node_name;
|
||||
|
||||
public string out_node_name;
|
||||
public string out_node_name;
|
||||
|
||||
public string in_lable_path;
|
||||
public string in_lable_path;
|
||||
|
||||
public int ResizeImageSize;
|
||||
public int segmentWidth;
|
||||
public int ImageWidth;
|
||||
|
||||
// public List<labelStringBase> OkClassTxtList;
|
||||
// public List<labelStringBase> OkClassTxtList;
|
||||
|
||||
|
||||
public List<ModelLabel> LabelNames;
|
||||
public List<ModelLabel> LabelNames;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
public enum ResultState
|
||||
{
|
||||
|
||||
|
||||
[Description("检测NG")]
|
||||
DetectNG = -3,
|
||||
|
||||
@ -120,20 +107,20 @@ namespace DH.Commons.Enums
|
||||
/// </summary>
|
||||
public class DetectionResultDetail
|
||||
{
|
||||
|
||||
|
||||
public string LabelBGR { get; set; }//识别到对象的标签BGR
|
||||
|
||||
|
||||
|
||||
public int LabelNo { get; set; } // 识别到对象的标签索引
|
||||
|
||||
|
||||
|
||||
public string LabelName { get; set; }//识别到对象的标签名称
|
||||
|
||||
|
||||
public double Score { get; set; }//识别目标结果的可能性、得分
|
||||
|
||||
|
||||
|
||||
public string LabelDisplay { get; set; }//识别到对象的 显示信息
|
||||
|
||||
|
||||
@ -154,10 +141,10 @@ namespace DH.Commons.Enums
|
||||
public class MLResult
|
||||
{
|
||||
public bool IsSuccess = false;
|
||||
|
||||
|
||||
public string ResultMessage;
|
||||
|
||||
|
||||
|
||||
public Bitmap ResultMap;
|
||||
|
||||
public List<DetectionResultDetail> ResultDetails = new List<DetectionResultDetail>();
|
||||
@ -181,8 +168,7 @@ namespace DH.Commons.Enums
|
||||
public bool IsGPU;
|
||||
public int GPUId;
|
||||
public float Score_thre;
|
||||
|
||||
|
||||
|
||||
public MLInit(string modelFile, bool isGPU, int gpuId, float score_thre)
|
||||
|
||||
|
||||
@ -205,31 +191,48 @@ namespace DH.Commons.Enums
|
||||
|
||||
}
|
||||
}
|
||||
public class DetectStationResult
|
||||
public class DetectStationResult
|
||||
{
|
||||
|
||||
public DateTime ImageTime { get; set; } = DateTime.Now;
|
||||
|
||||
private string id = "";
|
||||
public string Id
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
id = ImageTime.ToString("HHmmssfff");
|
||||
}
|
||||
return id;
|
||||
}
|
||||
set
|
||||
{
|
||||
id = value;
|
||||
}
|
||||
}
|
||||
public string Pid { get; set; }
|
||||
|
||||
|
||||
|
||||
public string TempPid { get; set; }
|
||||
public string TempPid { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 检测工位名称
|
||||
/// </summary>
|
||||
|
||||
public string DetectName { get; set; }
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 深度学习 检测结果
|
||||
/// </summary>
|
||||
public List<DetectionResultDetail> DetectDetails = new List<DetectionResultDetail>();
|
||||
public List<IShapeElement> DetectionResultShapes = new List<IShapeElement>();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 视觉测量结果集合
|
||||
/// </summary>
|
||||
|
||||
public List<IndexedSpec> realSpecs { get; set; } = new List<IndexedSpec>();
|
||||
/// <summary>
|
||||
/// 工位检测结果
|
||||
/// </summary>
|
||||
@ -254,36 +257,25 @@ namespace DH.Commons.Enums
|
||||
/// 预处理阶段已经NG
|
||||
/// </summary>
|
||||
public bool IsPreTreatNG { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 检测原图
|
||||
/// </summary>
|
||||
public Bitmap DetectionOriginImage { get; set; }
|
||||
/// <summary>
|
||||
/// 目标检测NG
|
||||
/// </summary>
|
||||
public bool IsObjectDetectNG { get; set; } = false;
|
||||
|
||||
public ImageFormat ImageFormat { get; set; } = ImageFormat.Jpeg;
|
||||
public DateTime EndTime { get; set; }
|
||||
|
||||
public string ImageSaveDirectory { get; set; }
|
||||
public int StationDetectElapsed { get; set; }
|
||||
public static string NormalizeAndClean(string input)
|
||||
{
|
||||
#pragma warning disable CS8603 // 可能返回 null 引用
|
||||
if (input == null) return null;
|
||||
#pragma warning restore CS8603 // 可能返回 null 引用
|
||||
public bool SaveOKOriginal = false;
|
||||
public bool SaveNGOriginal = false;
|
||||
public bool SaveOKDetect = false;
|
||||
public bool SaveNGDetect = false;
|
||||
|
||||
// Step 1: 标准化字符编码为 Form C (规范组合)
|
||||
string normalizedString = input.Normalize(NormalizationForm.FormC);
|
||||
|
||||
// Step 2: 移除所有空白字符,包括制表符和换行符
|
||||
string withoutWhitespace = Regex.Replace(normalizedString, @"\s+", "");
|
||||
|
||||
// Step 3: 移除控制字符 (Unicode 控制字符,范围 \u0000 - \u001F 和 \u007F)
|
||||
string withoutControlChars = Regex.Replace(withoutWhitespace, @"[\u0000-\u001F\u007F]+", "");
|
||||
|
||||
// Step 4: 移除特殊的不可见字符(如零宽度空格等)
|
||||
string cleanedString = Regex.Replace(withoutControlChars, @"[\u200B\u200C\u200D\uFEFF]+", "");
|
||||
|
||||
return cleanedString;
|
||||
}
|
||||
|
||||
}
|
||||
public class RelatedCamera : NotifyProperty
|
||||
{
|
||||
@ -406,7 +398,7 @@ namespace DH.Commons.Enums
|
||||
|
||||
public static double GetDistance(CustomizedPoint p1, CustomizedPoint p2)
|
||||
{
|
||||
return Math.Sqrt(Math.Pow((p1.X - p2.X), 2) + Math.Pow((p1.Y - p2.Y), 2));
|
||||
return Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2));
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
@ -447,13 +439,13 @@ namespace DH.Commons.Enums
|
||||
|
||||
public int CompareTo(CustomizedPoint other)
|
||||
{
|
||||
return (X == other.X && Y == other.Y) ? 0 : 1;
|
||||
return X == other.X && Y == other.Y ? 0 : 1;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
//return (int)(X * 10 + Y);
|
||||
return (new Tuple<double, double>(X, Y)).GetHashCode();
|
||||
return new Tuple<double, double>(X, Y).GetHashCode();
|
||||
}
|
||||
|
||||
public static CustomizedPoint operator -(CustomizedPoint p1, CustomizedPoint p2)
|
||||
@ -476,7 +468,7 @@ namespace DH.Commons.Enums
|
||||
// [Category("预处理参数")]
|
||||
// [DisplayName("参数名称")]
|
||||
// [Description("参数名称")]
|
||||
//
|
||||
//#pragma warning disable CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。
|
||||
// public string Name { get; set; }
|
||||
|
||||
|
||||
@ -488,7 +480,7 @@ namespace DH.Commons.Enums
|
||||
// [Category("预处理参数")]
|
||||
// [DisplayName("参数值")]
|
||||
// [Description("参数值")]
|
||||
//
|
||||
//#pragma warning disable CS8618 // 在退出构造函数时,不可为 null 的字段必须包含非 null 值。请考虑声明为可以为 null。
|
||||
// public string Value { get; set; }
|
||||
|
||||
|
||||
@ -496,48 +488,135 @@ namespace DH.Commons.Enums
|
||||
// }
|
||||
public class DetectionConfig : NotifyProperty
|
||||
{
|
||||
#region 基本信息
|
||||
[JsonPropertyName("id")]
|
||||
#region 属性字段
|
||||
private string _id = Guid.NewGuid().ToString();
|
||||
private string _name;
|
||||
private EnumDetectionType _detectionType= EnumDetectionType.深度学习;
|
||||
private string _cameraSourceId = "";
|
||||
private List<RelatedCamera> _cameraCollects = new List<RelatedCamera>();
|
||||
private bool _isEnableGPU;
|
||||
private bool _isMixModel;
|
||||
private bool _isPreEnabled;
|
||||
private bool _isEnabled;
|
||||
private bool _isAddStation = true;
|
||||
private string _halconAlgorithemPath_Pre;
|
||||
private AntList<PreTreatParam> _preTreatParams = new AntList<PreTreatParam>();
|
||||
private AntList<PreTreatParam> _outPreTreatParams = new AntList<PreTreatParam>();
|
||||
private ModelType _modelType = ModelType.目标检测;
|
||||
private string _modelPath;
|
||||
private int _modelWidth = 640;
|
||||
private int _modelHeight = 640;
|
||||
private string _modeloutNodeName = "output0";
|
||||
private float _modelconfThreshold = 0.5f;
|
||||
private string _in_lable_path;
|
||||
private AntList<DetectionLable> _detectionLableList = new AntList<DetectionLable>();
|
||||
private AntList<SizeTreatParam> _sizeTreatParamList = new AntList<SizeTreatParam>();
|
||||
|
||||
private CustomizedPoint _showLocation = new CustomizedPoint();
|
||||
private string _imageSaveDirectory= "D://PROJECTS//Images//";
|
||||
private bool _saveOKOriginal = false;
|
||||
private bool _saveNGOriginal = false;
|
||||
private bool _saveOKDetect = false;
|
||||
private bool _saveNGDetect = false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 属性声明
|
||||
[ReadOnly(true)]
|
||||
public string Id { get; private set; } = Guid.NewGuid().ToString();
|
||||
public string Id
|
||||
{
|
||||
get => _id;
|
||||
set
|
||||
{
|
||||
if (_id == value) return;
|
||||
_id = value;
|
||||
OnPropertyChanged(nameof(Id));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("检测配置")]
|
||||
[DisplayName("检测配置名称")]
|
||||
[Description("检测配置名称")]
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region 相机配置
|
||||
[Category("关联相机")]
|
||||
[DisplayName("关联相机")]
|
||||
[Description("关联相机描述")]
|
||||
[JsonPropertyName("camera_source_id")]
|
||||
public string CameraSourceId { get; set; } = "";
|
||||
public string Name
|
||||
{
|
||||
get => _name;
|
||||
set
|
||||
{
|
||||
if (_name == value) return;
|
||||
_name = value;
|
||||
OnPropertyChanged(nameof(Name));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("关联相机集合")]
|
||||
[DisplayName("关联相机集合")]
|
||||
[Description("关联相机描述")]
|
||||
[JsonPropertyName("camera_Collects")]
|
||||
public List<RelatedCamera> CameraCollects { get; set; } = new();
|
||||
#endregion
|
||||
public List<RelatedCamera> CameraCollects
|
||||
{
|
||||
get => _cameraCollects;
|
||||
set
|
||||
{
|
||||
if (_cameraCollects == value) return;
|
||||
_cameraCollects = value;
|
||||
OnPropertyChanged(nameof(CameraCollects));
|
||||
}
|
||||
}
|
||||
|
||||
#region 启用选项
|
||||
[Category("启用配置")]
|
||||
[DisplayName("是否启用GPU检测")]
|
||||
[JsonPropertyName("is_enable_gpu")]
|
||||
public bool IsEnableGPU { get; set; }
|
||||
[Description("是否启用GPU检测")]
|
||||
public bool IsEnableGPU
|
||||
{
|
||||
get => _isEnableGPU;
|
||||
set
|
||||
{
|
||||
if (_isEnableGPU == value) return;
|
||||
_isEnableGPU = value;
|
||||
OnPropertyChanged(nameof(IsEnableGPU));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("启用配置")]
|
||||
[DisplayName("是否混料模型")]
|
||||
[JsonPropertyName("is_mixModel")]
|
||||
public bool IsMixModel { get; set; }
|
||||
[Description("是否混料模型")]
|
||||
public bool IsMixModel
|
||||
{
|
||||
get => _isMixModel;
|
||||
set
|
||||
{
|
||||
if (_isMixModel == value) return;
|
||||
_isMixModel = value;
|
||||
OnPropertyChanged(nameof(IsMixModel));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("启用配置")]
|
||||
[DisplayName("是否启用预处理")]
|
||||
[Description("是否启用预处理")]
|
||||
public bool IsPreEnabled
|
||||
{
|
||||
get => _isPreEnabled;
|
||||
set
|
||||
{
|
||||
if (_isPreEnabled == value) return;
|
||||
_isPreEnabled = value;
|
||||
OnPropertyChanged(nameof(IsPreEnabled));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("启用配置")]
|
||||
[DisplayName("是否启用该检测")]
|
||||
[JsonPropertyName("is_enabled")]
|
||||
public bool IsEnabled { get; set; }
|
||||
[Description("是否启用该检测")]
|
||||
public bool IsEnabled
|
||||
{
|
||||
get => _isEnabled;
|
||||
set
|
||||
{
|
||||
if (_isEnabled == value) return;
|
||||
_isEnabled = value;
|
||||
OnPropertyChanged(nameof(IsEnabled));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("启用配置")]
|
||||
[DisplayName("是否启用预处理")]
|
||||
@ -548,133 +627,293 @@ namespace DH.Commons.Enums
|
||||
private bool _isAddStation;
|
||||
[Category("启用配置")]
|
||||
[DisplayName("是否加入检测工位")]
|
||||
[JsonPropertyName("is_addstation")]
|
||||
[Description("是否加入检测工位")]
|
||||
public bool IsAddStation
|
||||
{
|
||||
get => _isAddStation;
|
||||
set
|
||||
{
|
||||
if (_isAddStation != value)
|
||||
{
|
||||
_isAddStation = value;
|
||||
OnPropertyChanged(nameof(IsAddStation));
|
||||
}
|
||||
if (_isAddStation == value) return;
|
||||
_isAddStation = value;
|
||||
OnPropertyChanged(nameof(IsAddStation));
|
||||
}
|
||||
}
|
||||
[Category("图片保存")]
|
||||
[DisplayName("图片保存文件夹")]
|
||||
[Description("图片保存文件夹")]
|
||||
public virtual string ImageSaveDirectory
|
||||
{
|
||||
get => _imageSaveDirectory;
|
||||
set
|
||||
{
|
||||
if (_imageSaveDirectory == value) return;
|
||||
_imageSaveDirectory = value;
|
||||
OnPropertyChanged(nameof(ImageSaveDirectory));
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 预处理(视觉算子)
|
||||
[Category("1.预处理(视觉算子)")]
|
||||
[DisplayName("预处理-算法文件路径")]
|
||||
[JsonPropertyName("halcon_algorithemPath_pre")]
|
||||
public string HalconAlgorithemPath_Pre { get; set; }
|
||||
public string HalconAlgorithemPath_Pre
|
||||
{
|
||||
get => _halconAlgorithemPath_Pre;
|
||||
set
|
||||
{
|
||||
if (_halconAlgorithemPath_Pre == value) return;
|
||||
_halconAlgorithemPath_Pre = value;
|
||||
OnPropertyChanged(nameof(HalconAlgorithemPath_Pre));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("1.预处理(视觉算子)")]
|
||||
[DisplayName("预处理-参数列表")]
|
||||
[JsonPropertyName("pre_treatParams")]
|
||||
public List<PreTreatParam> PreTreatParams { get; set; } = new();
|
||||
|
||||
[Category("1.预处理(视觉算子)")]
|
||||
[DisplayName("预处理-输出参数列表")]
|
||||
[JsonPropertyName("out_preTreatParams")]
|
||||
public List<PreTreatParam> OUTPreTreatParams { get; set; } = new();
|
||||
#endregion
|
||||
|
||||
#region 深度学习检测
|
||||
[Category("2.中检测(深度学习)")]
|
||||
[DisplayName("模型类型")]
|
||||
[JsonPropertyName("model_Type")]
|
||||
public MLModelType ModelType { get; set; } = MLModelType.ObjectDetection;
|
||||
|
||||
[Category("2.中检测(深度学习)")]
|
||||
[DisplayName("模型文件路径")]
|
||||
[JsonPropertyName("model_Path")]
|
||||
public string ModelPath { get; set; }
|
||||
|
||||
[Category("2.中检测(深度学习)")]
|
||||
[DisplayName("模型宽度")]
|
||||
[JsonPropertyName("model_Width")]
|
||||
public int ModelWidth { get; set; } = 640;
|
||||
|
||||
[Category("2.中检测(深度学习)")]
|
||||
[DisplayName("模型高度")]
|
||||
[JsonPropertyName("model_Height")]
|
||||
public int ModelHeight { get; set; } = 640;
|
||||
|
||||
[Category("2.中检测(深度学习)")]
|
||||
[DisplayName("模型节点名称")]
|
||||
[JsonPropertyName("model_outNodeName")]
|
||||
public string ModeloutNodeName { get; set; } = "output0";
|
||||
|
||||
[Category("2.中检测(深度学习)")]
|
||||
[DisplayName("模型置信度")]
|
||||
[JsonPropertyName("model_confThreshold")]
|
||||
public float ModelconfThreshold { get; set; } = 0.5f;
|
||||
|
||||
[Category("2.中检测(深度学习)")]
|
||||
[DisplayName("模型标签路径")]
|
||||
[JsonPropertyName("in_lablepath")]
|
||||
public string in_lable_path { get; set; }
|
||||
#endregion
|
||||
|
||||
#region 尺寸测量
|
||||
|
||||
// public List<SizeTreatParam> PreTreatCollects { get; set; } = new();
|
||||
private List<SizeTreatParam> _preTreatParams = new();
|
||||
|
||||
[Category("1.尺寸测量集合")]
|
||||
[DisplayName("尺寸测量集合")]
|
||||
[JsonPropertyName("Pre_TreatCollects")]
|
||||
public List<SizeTreatParam> PreTreatCollects
|
||||
[Description("预处理-参数列表")]
|
||||
public AntList<PreTreatParam> PreTreatParams
|
||||
{
|
||||
get => _preTreatParams;
|
||||
set
|
||||
{
|
||||
if (_preTreatParams != value)
|
||||
{
|
||||
_preTreatParams = value;
|
||||
OnPropertyChanged(nameof(PreTreatCollects));
|
||||
|
||||
}
|
||||
if (_preTreatParams == value) return;
|
||||
_preTreatParams = value;
|
||||
OnPropertyChanged(nameof(PreTreatParams));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
[Category("1.预处理(视觉算子)")]
|
||||
[DisplayName("预处理-输出参数列表")]
|
||||
[Description("预处理-输出参数列表")]
|
||||
public AntList<PreTreatParam> OUTPreTreatParams
|
||||
{
|
||||
get => _outPreTreatParams;
|
||||
set
|
||||
{
|
||||
if (_outPreTreatParams == value) return;
|
||||
_outPreTreatParams = value;
|
||||
OnPropertyChanged(nameof(OUTPreTreatParams));
|
||||
}
|
||||
}
|
||||
|
||||
#region 过滤器
|
||||
[Category("4.最终过滤(逻辑过滤)")]
|
||||
[DisplayName("过滤器集合")]
|
||||
[JsonPropertyName("detection_filterList")]
|
||||
public List<DetectionFilter> DetectionFilterList { get; set; } = new();
|
||||
#endregion
|
||||
[Category("2.中检测(深度学习)")]
|
||||
[DisplayName("中检测-模型类型")]
|
||||
[Description("模型类型:ImageClassification-图片分类;ObjectDetection:目标检测;Segmentation-图像分割")]
|
||||
public ModelType ModelType
|
||||
{
|
||||
get => _modelType;
|
||||
set
|
||||
{
|
||||
if (_modelType == value) return;
|
||||
_modelType = value;
|
||||
OnPropertyChanged(nameof(ModelType));
|
||||
}
|
||||
}
|
||||
|
||||
#region 其他信息
|
||||
[JsonPropertyName("Detection_LableList")]
|
||||
public List<DetectionLable> DetectionLableList { get; set; } = new();
|
||||
[Category("2.中检测(深度学习)")]
|
||||
[DisplayName("中检测-模型文件路径")]
|
||||
[Description("中处理 深度学习模型文件路径")]
|
||||
public string ModelPath
|
||||
{
|
||||
get => _modelPath;
|
||||
set
|
||||
{
|
||||
if (_modelPath == value) return;
|
||||
_modelPath = value;
|
||||
OnPropertyChanged(nameof(ModelPath));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("2.中检测(深度学习)")]
|
||||
[DisplayName("中检测-模型宽度")]
|
||||
[Description("中处理-模型宽度")]
|
||||
public int ModelWidth
|
||||
{
|
||||
get => _modelWidth;
|
||||
set
|
||||
{
|
||||
if (_modelWidth == value) return;
|
||||
_modelWidth = value;
|
||||
OnPropertyChanged(nameof(ModelWidth));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("2.中检测(深度学习)")]
|
||||
[DisplayName("中检测-模型高度")]
|
||||
[Description("中处理-模型高度")]
|
||||
public int ModelHeight
|
||||
{
|
||||
get => _modelHeight;
|
||||
set
|
||||
{
|
||||
if (_modelHeight == value) return;
|
||||
_modelHeight = value;
|
||||
OnPropertyChanged(nameof(ModelHeight));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("2.中检测(深度学习)")]
|
||||
[DisplayName("中检测-模型节点名称")]
|
||||
[Description("中处理-模型节点名称")]
|
||||
public string ModeloutNodeName
|
||||
{
|
||||
get => _modeloutNodeName;
|
||||
set
|
||||
{
|
||||
if (_modeloutNodeName == value) return;
|
||||
_modeloutNodeName = value;
|
||||
OnPropertyChanged(nameof(ModeloutNodeName));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("2.中检测(深度学习)")]
|
||||
[DisplayName("中检测-模型置信度")]
|
||||
[Description("中处理-模型置信度")]
|
||||
public float ModelconfThreshold
|
||||
{
|
||||
get => _modelconfThreshold;
|
||||
set
|
||||
{
|
||||
if (_modelconfThreshold == value) return;
|
||||
_modelconfThreshold = value;
|
||||
OnPropertyChanged(nameof(ModelconfThreshold));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("2.中检测(深度学习)")]
|
||||
[DisplayName("中检测-模型标签路径")]
|
||||
[Description("中处理-模型标签路径")]
|
||||
public string In_lable_path
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(ModelPath) || string.IsNullOrWhiteSpace(ModelPath))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
string dir = Path.GetDirectoryName(ModelPath);
|
||||
string file = $"{Path.GetFileNameWithoutExtension(ModelPath)}.txt";
|
||||
return Path.Combine(dir, file);
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_in_lable_path == value) return;
|
||||
_in_lable_path = value;
|
||||
OnPropertyChanged(nameof(In_lable_path));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("检测配置")]
|
||||
[DisplayName("检测类型")]
|
||||
[Description("检测类型")]
|
||||
public EnumDetectionType DetectionType
|
||||
{
|
||||
get => _detectionType;
|
||||
set
|
||||
{
|
||||
if (_detectionType == value) return;
|
||||
_detectionType = value;
|
||||
OnPropertyChanged(nameof(DetectionType));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("显示配置")]
|
||||
[DisplayName("显示位置")]
|
||||
[JsonPropertyName("Show_Location")]
|
||||
public CustomizedPoint ShowLocation { get; set; } = new();
|
||||
#endregion
|
||||
//public event PropertyChangedEventHandler PropertyChanged;
|
||||
[Description("检测信息显示位置")]
|
||||
public CustomizedPoint ShowLocation
|
||||
{
|
||||
get => _showLocation;
|
||||
set
|
||||
{
|
||||
if (_showLocation == value) return;
|
||||
_showLocation = value;
|
||||
OnPropertyChanged(nameof(ShowLocation));
|
||||
}
|
||||
}
|
||||
|
||||
//protected virtual void OnPropertyChanged(string propertyName)
|
||||
//{
|
||||
// PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
//}
|
||||
/// <summary>
|
||||
/// 标签集合(需确保DetectionLable也实现INotifyPropertyChanged)
|
||||
/// </summary>
|
||||
public AntList<DetectionLable> DetectionLableList
|
||||
{
|
||||
get => _detectionLableList;
|
||||
set
|
||||
{
|
||||
if (_detectionLableList == value) return;
|
||||
_detectionLableList = value;
|
||||
OnPropertyChanged(nameof(DetectionLableList));
|
||||
}
|
||||
}
|
||||
|
||||
public AntList<SizeTreatParam> SizeTreatParamList
|
||||
{
|
||||
get => _sizeTreatParamList;
|
||||
set
|
||||
{
|
||||
if (_sizeTreatParamList == value) return;
|
||||
_sizeTreatParamList = value;
|
||||
OnPropertyChanged(nameof(SizeTreatParamList));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool SaveOKOriginal
|
||||
{
|
||||
get => _saveOKOriginal;
|
||||
set
|
||||
{
|
||||
if (_saveOKOriginal == value) return;
|
||||
_saveOKOriginal = value;
|
||||
OnPropertyChanged(nameof(SaveOKOriginal));
|
||||
}
|
||||
}
|
||||
|
||||
public bool SaveNGOriginal
|
||||
{
|
||||
get => _saveNGOriginal;
|
||||
set
|
||||
{
|
||||
if (_saveNGOriginal == value) return;
|
||||
_saveNGOriginal = value;
|
||||
OnPropertyChanged(nameof(SaveNGOriginal));
|
||||
}
|
||||
}
|
||||
public bool SaveOKDetect
|
||||
{
|
||||
get => _saveOKDetect;
|
||||
set
|
||||
{
|
||||
if (_saveOKDetect == value) return;
|
||||
_saveOKDetect = value;
|
||||
OnPropertyChanged(nameof(SaveOKDetect));
|
||||
}
|
||||
}
|
||||
public bool SaveNGDetect
|
||||
{
|
||||
get => _saveNGDetect;
|
||||
set
|
||||
{
|
||||
if (_saveNGDetect == value) return;
|
||||
_saveNGDetect = value;
|
||||
OnPropertyChanged(nameof(SaveNGDetect));
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 构造函数
|
||||
public DetectionConfig() { }
|
||||
|
||||
public DetectionConfig(string name, MLModelType modelType, string modelPath, bool isEnableGPU, string sCameraSourceId)
|
||||
public DetectionConfig(
|
||||
string name,
|
||||
ModelType modelType,
|
||||
string modelPath,
|
||||
bool isEnableGPU,
|
||||
string sCameraSourceId)
|
||||
{
|
||||
// 通过属性赋值触发通知
|
||||
ModelPath = modelPath ?? string.Empty;
|
||||
Name = name;
|
||||
ModelType = modelType;
|
||||
ModelPath = modelPath ?? string.Empty;
|
||||
IsEnableGPU = isEnableGPU;
|
||||
CameraSourceId = sCameraSourceId;
|
||||
Id = Guid.NewGuid().ToString();
|
||||
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@ -727,6 +966,7 @@ namespace DH.Commons.Enums
|
||||
}
|
||||
|
||||
private CellLink[] cellLinks;
|
||||
[JsonIgnore]
|
||||
public CellLink[] CellLinks
|
||||
{
|
||||
get {
|
||||
@ -747,17 +987,18 @@ namespace DH.Commons.Enums
|
||||
public class DetectionLable : NotifyProperty
|
||||
{
|
||||
private bool _selected = false;
|
||||
|
||||
private string _labelId;
|
||||
private string _labelName;
|
||||
private double _maxSource;
|
||||
private double _minSource;
|
||||
private double _maxScore;
|
||||
private double _minScore;
|
||||
private double _maxArea;
|
||||
private double _minArea;
|
||||
private ResultState _resultState = ResultState.ResultTBD;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public bool Selected
|
||||
{
|
||||
get { return _selected; }
|
||||
@ -792,27 +1033,26 @@ namespace DH.Commons.Enums
|
||||
OnPropertyChanged(nameof(LabelName));
|
||||
}
|
||||
}
|
||||
[JsonPropertyName("maxSource")]
|
||||
public double MaxSource
|
||||
|
||||
public double MaxScore
|
||||
{
|
||||
get { return _maxSource; }
|
||||
get { return _maxScore; }
|
||||
set
|
||||
{
|
||||
if (_maxSource.Equals(value)) return;
|
||||
_maxSource = value;
|
||||
OnPropertyChanged(nameof(MaxSource));
|
||||
if (_maxScore.Equals(value)) return;
|
||||
_maxScore = value;
|
||||
OnPropertyChanged(nameof(MaxScore));
|
||||
}
|
||||
}
|
||||
|
||||
[JsonPropertyName("minSource")]
|
||||
public double MinSource
|
||||
public double MinScore
|
||||
{
|
||||
get { return _minSource; }
|
||||
get { return _minScore; }
|
||||
set
|
||||
{
|
||||
if (_minSource.Equals(value)) return;
|
||||
_minSource = value;
|
||||
OnPropertyChanged(nameof(MinSource));
|
||||
if (_minScore.Equals(value)) return;
|
||||
_minScore = value;
|
||||
OnPropertyChanged(nameof(MinScore));
|
||||
}
|
||||
}
|
||||
[JsonPropertyName("maxArea")]
|
||||
@ -850,6 +1090,7 @@ namespace DH.Commons.Enums
|
||||
}
|
||||
|
||||
private CellLink[] cellLinks;
|
||||
[JsonIgnore]
|
||||
public CellLink[] CellLinks
|
||||
{
|
||||
get {
|
||||
@ -862,6 +1103,15 @@ namespace DH.Commons.Enums
|
||||
OnPropertyChanged(nameof(CellLinks));
|
||||
}
|
||||
}
|
||||
|
||||
public bool FilterOperation(DetectionResultDetail recongnitionResult)
|
||||
{
|
||||
|
||||
double compareValue = recongnitionResult.Area;
|
||||
double compareScoreValue = recongnitionResult.Score;
|
||||
return (compareValue >= MinArea && compareValue <= MaxArea)&& (compareScoreValue >= MinScore && compareScoreValue <= MaxScore);
|
||||
|
||||
}
|
||||
}
|
||||
public class PreTreatCollect
|
||||
{
|
||||
@ -999,7 +1249,7 @@ namespace DH.Commons.Enums
|
||||
_resultShow = value;
|
||||
OnPropertyChanged(nameof(ResultShow));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public string OutResultShow
|
||||
@ -1013,19 +1263,20 @@ namespace DH.Commons.Enums
|
||||
}
|
||||
}
|
||||
|
||||
//public string PrePath
|
||||
//{
|
||||
// get { return _prePath; }
|
||||
// set
|
||||
// {
|
||||
// if (_prePath.Equals(value)) return;
|
||||
// _prePath = value;
|
||||
// OnPropertyChanged(nameof(PrePath));
|
||||
// }
|
||||
//}
|
||||
|
||||
public string PrePath
|
||||
{
|
||||
get { return _prePath; }
|
||||
set
|
||||
{
|
||||
if (_prePath.Equals(value)) return;
|
||||
_prePath = value;
|
||||
OnPropertyChanged(nameof(PrePath));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private CellLink[] cellLinks;
|
||||
[JsonIgnore]
|
||||
public CellLink[] CellLinks
|
||||
{
|
||||
get { return cellLinks; }
|
||||
@ -1063,9 +1314,9 @@ namespace DH.Commons.Enums
|
||||
//[TypeConverter(typeof(LabelCategoryConverter))]
|
||||
public string LabelCategory { get; set; } = "";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -1126,8 +1377,8 @@ namespace DH.Commons.Enums
|
||||
//public string GetLabelName()
|
||||
//{
|
||||
// var name = "";
|
||||
|
||||
|
||||
|
||||
|
||||
// var mlBase = iConfig.DeviceConfigs.FirstOrDefault(c => c is VisionEngineInitialConfigBase) as VisionEngineInitialConfigBase;
|
||||
// if (mlBase != null)
|
||||
// {
|
||||
@ -1138,7 +1389,7 @@ namespace DH.Commons.Enums
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// return name;
|
||||
//}
|
||||
}
|
||||
@ -1199,11 +1450,11 @@ namespace DH.Commons.Enums
|
||||
[DisplayName("过滤条件集合")]
|
||||
[Description("过滤条件集合,集合之间为“且”关系")]
|
||||
//[TypeConverter(typeof(CollectionCountConvert))]
|
||||
// [Editor(typeof(ComplexCollectionEditor<FilterConditions>), typeof(UITypeEditor))]
|
||||
// [Editor(typeof(ComplexCollectionEditor<FilterConditions>), typeof(UITypeEditor))]
|
||||
public List<FilterConditions> FilterConditionsCollection { get; set; } = new List<FilterConditions>();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public bool FilterOperation(DetectionResultDetail recongnitionResult)
|
||||
{
|
||||
return FilterConditionsCollection.All(u =>
|
389
DH.Commons/Base/DeviceBase.cs
Normal file
389
DH.Commons/Base/DeviceBase.cs
Normal file
@ -0,0 +1,389 @@
|
||||
|
||||
using DH.Commons.Enums;
|
||||
using OpenCvSharp.Internal;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using static DH.Commons.Enums.EnumHelper;
|
||||
using Timer = System.Threading.Timer;
|
||||
|
||||
namespace DH.Commons.Base
|
||||
{
|
||||
public abstract class DeviceBase : IDisposable
|
||||
{
|
||||
#region Event
|
||||
[JsonIgnore]
|
||||
[Browsable(false)]
|
||||
public Action<DateTime, Exception> OnExceptionOccured { get; set; }
|
||||
//public event Action<DateTime, LogLevel, string> OnLog;
|
||||
public event Action<LogMsg> OnLog;
|
||||
// public event Action<IDevice, DeviceState> OnDeviceStateChanged;
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
#endregion
|
||||
|
||||
#region field
|
||||
int RetryTime = 3;
|
||||
/// <summary>
|
||||
/// 和设备暂停状态关联的信号量
|
||||
/// </summary>
|
||||
private readonly ManualResetEvent pauseHandle = new ManualResetEvent(true);
|
||||
readonly Timer stateChangedTimer;
|
||||
#endregion
|
||||
|
||||
#region Property
|
||||
#region State
|
||||
private EnumHelper.DeviceState _currentStateToBe = EnumHelper.DeviceState.DSUninit;
|
||||
/// <summary>
|
||||
/// 当前设备状态
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
internal EnumHelper.DeviceState CurrentStateToBe
|
||||
{
|
||||
get
|
||||
{
|
||||
return _currentStateToBe;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _currentStateToBe)
|
||||
{
|
||||
var initialState = _currentStateToBe;
|
||||
_currentStateToBe = value;
|
||||
|
||||
if (_currentStateToBe != EnumHelper.DeviceState.DSExcept)
|
||||
{
|
||||
// OnStateChanged(initialState);
|
||||
}
|
||||
else
|
||||
{
|
||||
stateChangedTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//private EnumHelper.DeviceState initialState = EnumHelper.DeviceState.DSUninit;
|
||||
private EnumHelper.DeviceState _currentState = EnumHelper.DeviceState.DSUninit;
|
||||
public EnumHelper.DeviceState CurrentState
|
||||
{
|
||||
get
|
||||
{
|
||||
return _currentState;
|
||||
}
|
||||
set
|
||||
{
|
||||
_currentState = value;
|
||||
|
||||
if (value != EnumHelper.DeviceState.TBD)
|
||||
{
|
||||
// OnDeviceStateChanged?.Invoke(this, _currentState);
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CurrentState"));
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// initialState = _currentState;
|
||||
//}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 设备标识符 从数据库获取
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设备名称 从数据库获取
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
//private IInitialConfig initialConfig = null;
|
||||
///// <summary>
|
||||
///// 设备初始化配置 从数据库获取
|
||||
///// </summary>
|
||||
//public virtual IInitialConfig InitialConfig
|
||||
//{
|
||||
// get => initialConfig;
|
||||
// set
|
||||
// {
|
||||
// initialConfig = value;
|
||||
// Id = initialConfig.Id;
|
||||
// Name = initialConfig.Name;
|
||||
|
||||
// LoggerHelper.LogPath = initialConfig.LogPath;
|
||||
// LoggerHelper.LogPrefix = initialConfig.Name;
|
||||
// }
|
||||
//}
|
||||
#endregion
|
||||
|
||||
#region 构造函数
|
||||
public DeviceBase()
|
||||
{
|
||||
RegisterFileWriterException();
|
||||
// stateChangedTimer = new Timer(new TimerCallback(CheckDeviceOpTimeOut), null, Timeout.Infinite, Timeout.Infinite);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 设备抽象方法
|
||||
protected virtual void Init()
|
||||
{
|
||||
LogAsync(DateTime.Now, LogLevel.Information, $"{Name}初始化完成");
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
LogAsync(DateTime.Now, LogLevel.Information, $"{Name}启动");
|
||||
}
|
||||
|
||||
protected virtual void Stop()
|
||||
{
|
||||
LogAsync(DateTime.Now, LogLevel.Information, $"{Name}停止");
|
||||
}
|
||||
|
||||
//public abstract void AttachToProcess(IProcess process);
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 常用操作封装方法
|
||||
/// </summary>
|
||||
/// <param name="opConfig"></param>
|
||||
/// <returns></returns>
|
||||
//public virtual ResponseMessage RunWrap(IOperationConfig opConfig)
|
||||
//{
|
||||
// ResponseMessage msg = new ResponseMessage();
|
||||
// msg.Message = "设备基类默认操作";
|
||||
// return msg;
|
||||
//}
|
||||
|
||||
#region 状态切换
|
||||
//[DeviceExceptionAspect]
|
||||
//public void StateChange(EnumHelper.DeviceState stateToBe)
|
||||
//{
|
||||
// if (CurrentState == stateToBe)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (!stateToBe.CheckPreStateValid((int)CurrentStateToBe))
|
||||
// {
|
||||
// string currentStateStr = CurrentStateToBe.GetEnumDescription();
|
||||
// string stateToBeStr = stateToBe.GetEnumDescription();
|
||||
// throw new ProcessException($"{InitialConfig.Name}设备的当前状态为{currentStateStr},无法切换至{stateToBeStr}");
|
||||
// }
|
||||
|
||||
// CurrentState = EnumHelper.DeviceState.TBD;
|
||||
// CurrentStateToBe = stateToBe;
|
||||
//}
|
||||
|
||||
//[DeviceExceptionAspect]
|
||||
//private void OnStateChanged(EnumHelper.DeviceState initialState)
|
||||
//{
|
||||
// try
|
||||
// {
|
||||
// if (CurrentStateToBe != EnumHelper.DeviceState.DSExcept)
|
||||
// {
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (CurrentState == EnumHelper.DeviceState.DSExcept)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// throw new ProcessException($"{InitialConfig.Name}设备操作超时");
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (RetryTime >= 0)
|
||||
// {
|
||||
// if (initialState == CurrentStateToBe)
|
||||
// {
|
||||
// CurrentState = CurrentStateToBe;
|
||||
// return;
|
||||
// }
|
||||
|
||||
// #region 状态切换操作
|
||||
// switch (CurrentStateToBe)
|
||||
// {
|
||||
// case EnumHelper.DeviceState.DSInit:
|
||||
// if (initialState == EnumHelper.DeviceState.DSOpen)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Init();
|
||||
// }
|
||||
// break;
|
||||
// case EnumHelper.DeviceState.DSOpen:
|
||||
// if (initialState == EnumHelper.DeviceState.DSInit)
|
||||
// {
|
||||
// Start();
|
||||
// }
|
||||
// else if (initialState == EnumHelper.DeviceState.DSPause)
|
||||
// {
|
||||
// Resume();
|
||||
// pauseHandle.Set();
|
||||
// }
|
||||
// break;
|
||||
// case EnumHelper.DeviceState.DSPause:
|
||||
// pauseHandle.Reset();
|
||||
// Pause();
|
||||
// break;
|
||||
// case EnumHelper.DeviceState.DSClose:
|
||||
// if (initialState != DeviceState.DSUninit)
|
||||
// {
|
||||
// Stop();
|
||||
// }
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
|
||||
// RetryTime = 3;
|
||||
// CurrentState = CurrentStateToBe;
|
||||
// #endregion
|
||||
// }
|
||||
|
||||
// stateChangedTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// RetryTime--;
|
||||
// if (RetryTime > 0)
|
||||
// {
|
||||
// OnStateChanged(initialState);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (CurrentState != EnumHelper.DeviceState.DSExcept)
|
||||
// {
|
||||
// RetryTime = 3;
|
||||
// throw new ProcessException($"设备{InitialConfig.Name}的{CurrentStateToBe.GetEnumDescription()}操作重复3次失败", ex, ExceptionLevel.Warning);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
//private void CheckDeviceOpTimeOut(object state)
|
||||
//{
|
||||
// stateChangedTimer?.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
|
||||
// if (CurrentState != EnumHelper.DeviceState.DSExcept)
|
||||
// {
|
||||
// StateChange(EnumHelper.DeviceState.DSExcept);
|
||||
// }
|
||||
//}
|
||||
#endregion
|
||||
|
||||
#region 日志处理
|
||||
private void RegisterFileWriterException()
|
||||
{
|
||||
LoggerHelper.OnLogExceptionRaised -= LoggerHelper_OnLogExceptionRaised;
|
||||
// CSVHelper.OnCSVExceptionRaised -= LoggerHelper_OnLogExceptionRaised;
|
||||
|
||||
LoggerHelper.OnLogExceptionRaised += LoggerHelper_OnLogExceptionRaised;
|
||||
// CSVHelper.OnCSVExceptionRaised += LoggerHelper_OnLogExceptionRaised;
|
||||
}
|
||||
// public CSVHelper CSVHelper { get; set; } = new CSVHelper();
|
||||
|
||||
public LoggerHelper LoggerHelper { get; set; } = new LoggerHelper();
|
||||
|
||||
public virtual void LogAsync(LogMsg msg)
|
||||
{
|
||||
msg.MsgSource = Name;
|
||||
msg.ThreadId = Thread.CurrentThread.ManagedThreadId;
|
||||
|
||||
//OnLog?.BeginInvoke(msg, null, null);
|
||||
OnLog?.Invoke(msg);
|
||||
|
||||
//if (InitialConfig.IsEnableLog)
|
||||
//{
|
||||
LoggerHelper.LogAsync(msg);
|
||||
//}
|
||||
}
|
||||
|
||||
public virtual void LogAsync(DateTime dt, LogLevel logLevel, string msg)
|
||||
{
|
||||
LogAsync(new LogMsg(dt, logLevel, msg));
|
||||
}
|
||||
private void LoggerHelper_OnLogExceptionRaised(DateTime dt, string msg)
|
||||
{
|
||||
OnLog?.Invoke(new LogMsg(dt, LogLevel.Error, msg));
|
||||
}
|
||||
/// <summary>
|
||||
/// CSV异步数据输出
|
||||
/// </summary>
|
||||
/// <param name="csvFile">CSV输出文件的文件全路径</param>
|
||||
/// <param name="csvData">CSV输出数据</param>
|
||||
/// <param name="csvHead">CSV文件表头</param>
|
||||
public virtual void CSVRecordAsync(string csvFile, string csvData, string csvHead = "")
|
||||
{
|
||||
// CSVHelper.CSVOutputAsync(csvFile, csvData, csvHead);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 报警记录
|
||||
//object _alarmLock = new object();
|
||||
//protected virtual async void SaveAlarmCSVAsync(DateTime now, string deviceName, IWarningSet ws)
|
||||
//{
|
||||
// await Task.Run(() =>
|
||||
// {
|
||||
// LogAsync(now, LogLevel.Warning, $"{ws.WarningCode}-{ws.WarningDescription} {(ws.CurrentStatus ? "发生" : "取消")}");
|
||||
|
||||
// if (string.IsNullOrWhiteSpace(this.InitialConfig.LogPath) || !InitialConfig.IsEnableCSV)
|
||||
// return;
|
||||
|
||||
// string path = Path.Combine(InitialConfig.LogPath, $"Alarm_{Name}_{now.ToString("yyyyMMdd")}.csv");
|
||||
// string head = "Time,Source,AlarmCode,AlarmDescription,AlarmStatus";
|
||||
// string data = $"{now.ToString("HH:mm:ss.fff")},{deviceName},{ws.WarningCode},{ws.WarningDescription},{(ws.CurrentStatus ? "报警发生" : "报警取消")}";
|
||||
// CSVRecordAsync(path, data, head);
|
||||
// });
|
||||
//}
|
||||
#endregion
|
||||
|
||||
#region IDisposable Support
|
||||
private bool disposedValue = false; // 要检测冗余调用
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
//释放托管状态(托管对象)。
|
||||
stateChangedTimer?.Dispose();
|
||||
pauseHandle?.Dispose();
|
||||
}
|
||||
|
||||
// TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
|
||||
// TODO: 将大型字段设置为 null。
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。
|
||||
// ~DeviceBase()
|
||||
// {
|
||||
// // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
|
||||
// Dispose(false);
|
||||
// }
|
||||
|
||||
// 添加此代码以正确实现可处置模式。
|
||||
public void Dispose()
|
||||
{
|
||||
// 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
|
||||
Dispose(true);
|
||||
// TODO: 如果在以上内容中替代了终结器,则取消注释以下行。
|
||||
// GC.SuppressFinalize(this);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
169
DH.Commons/Base/GlobalConfig.cs
Normal file
169
DH.Commons/Base/GlobalConfig.cs
Normal file
@ -0,0 +1,169 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using AntdUI;
|
||||
|
||||
namespace DH.Commons.Base
|
||||
{
|
||||
public class GlobalConfig : NotifyProperty
|
||||
{
|
||||
bool _EnableVibrator=false;
|
||||
bool _EnableBelt = false;
|
||||
int _ClearTime=0;
|
||||
string _name;
|
||||
private BindingList<PLCItem> _InitProcessList = new BindingList<PLCItem>();
|
||||
private BindingList<PLCItem> _StartProcessList = new BindingList<PLCItem>();
|
||||
private BindingList<PLCItem> _StopProcessList = new BindingList<PLCItem>();
|
||||
private BindingList<PLCItem> _StartResetList = new BindingList<PLCItem>();
|
||||
private BindingList<PLCItem> _StopResetList = new BindingList<PLCItem>();
|
||||
public string Name
|
||||
{
|
||||
get => _name;
|
||||
set
|
||||
{
|
||||
if (_name != value)
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(nameof(Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool EnableBelt
|
||||
{
|
||||
get => _EnableBelt;
|
||||
set
|
||||
{
|
||||
if (_EnableBelt != value)
|
||||
{
|
||||
_EnableBelt = value;
|
||||
OnPropertyChanged(nameof(EnableBelt));
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool EnableVibrator
|
||||
{
|
||||
get => _EnableVibrator;
|
||||
set
|
||||
{
|
||||
if (_EnableVibrator != value)
|
||||
{
|
||||
_EnableVibrator = value;
|
||||
OnPropertyChanged(nameof(EnableVibrator));
|
||||
}
|
||||
}
|
||||
}
|
||||
public int ClearTime
|
||||
{
|
||||
get => _ClearTime;
|
||||
set
|
||||
{
|
||||
if (_ClearTime != value)
|
||||
{
|
||||
_ClearTime = value;
|
||||
OnPropertyChanged(nameof(ClearTime));
|
||||
}
|
||||
}
|
||||
}
|
||||
public BindingList<PLCItem> InitProcessList
|
||||
{
|
||||
get => _InitProcessList;
|
||||
set
|
||||
{
|
||||
if (_InitProcessList == value) return;
|
||||
_InitProcessList = value;
|
||||
OnPropertyChanged(nameof(InitProcessList));
|
||||
}
|
||||
}
|
||||
public BindingList<PLCItem> StartProcessList
|
||||
{
|
||||
get => _StartProcessList;
|
||||
set
|
||||
{
|
||||
if (_StartProcessList == value) return;
|
||||
_StartProcessList = value;
|
||||
OnPropertyChanged(nameof(StartProcessList));
|
||||
}
|
||||
}
|
||||
public BindingList<PLCItem> StopProcessList
|
||||
{
|
||||
get => _StopProcessList;
|
||||
set
|
||||
{
|
||||
if (_StopProcessList == value) return;
|
||||
_StopProcessList = value;
|
||||
OnPropertyChanged(nameof(StopProcessList));
|
||||
}
|
||||
}
|
||||
public BindingList<PLCItem> StartResetList
|
||||
{
|
||||
get => _StartResetList;
|
||||
set
|
||||
{
|
||||
if (_StartResetList == value) return;
|
||||
_StartResetList = value;
|
||||
OnPropertyChanged(nameof(StartResetList));
|
||||
}
|
||||
}
|
||||
public BindingList<PLCItem> StopResetList
|
||||
{
|
||||
get => _StopResetList;
|
||||
set
|
||||
{
|
||||
if (_StopResetList == value) return;
|
||||
_StopResetList = value;
|
||||
OnPropertyChanged(nameof(StopResetList));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
string _imgSavePath;
|
||||
string _dbSavePath;
|
||||
string _configSavePath;
|
||||
|
||||
public string ImgSavePath
|
||||
{
|
||||
get => _imgSavePath;
|
||||
set
|
||||
{
|
||||
if (_imgSavePath != value)
|
||||
{
|
||||
_imgSavePath = value;
|
||||
OnPropertyChanged(nameof(ImgSavePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string DbSavePath
|
||||
{
|
||||
get => _dbSavePath;
|
||||
set
|
||||
{
|
||||
if (_dbSavePath != value)
|
||||
{
|
||||
_dbSavePath = value;
|
||||
OnPropertyChanged(nameof(DbSavePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string ConfigSavePath
|
||||
{
|
||||
get => _configSavePath;
|
||||
set
|
||||
{
|
||||
if (_configSavePath != value)
|
||||
{
|
||||
_configSavePath = value;
|
||||
OnPropertyChanged(nameof(ConfigSavePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
378
DH.Commons/Base/PLCBase.cs
Normal file
378
DH.Commons/Base/PLCBase.cs
Normal file
@ -0,0 +1,378 @@
|
||||
using System.ComponentModel;
|
||||
using System.IO.Ports;
|
||||
using System.Text.Json.Serialization;
|
||||
using AntdUI;
|
||||
using DH.Commons.Enums; // 请确保此命名空间包含EnumPLCType
|
||||
|
||||
namespace DH.Commons.Base
|
||||
{
|
||||
public class PLCBase : NotifyProperty
|
||||
{
|
||||
|
||||
// 私有字段
|
||||
private bool _enable;
|
||||
private bool _connected;
|
||||
private string _plcName;
|
||||
private EnumPLCType _plcType;
|
||||
private string _com = "COM1";
|
||||
private int _baudRate = 9600;
|
||||
private int _dataBit = 8;
|
||||
private StopBits _stopBit = StopBits.One;
|
||||
private Parity _parity = Parity.None;
|
||||
private string _ip = "192.168.6.61";
|
||||
private int _port = 502;
|
||||
private BindingList<PLCItem> _PLCItemList = new BindingList<PLCItem>();
|
||||
|
||||
[Category("设备配置")]
|
||||
[DisplayName("是否启用")]
|
||||
[Description("是否启用")]
|
||||
public bool Enable
|
||||
{
|
||||
get => _enable;
|
||||
set
|
||||
{
|
||||
if (_enable == value) return;
|
||||
_enable = value;
|
||||
OnPropertyChanged(nameof(Enable));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Category("状态监控")]
|
||||
[DisplayName("连接状态")]
|
||||
[Description("PLC连接状态")]
|
||||
public bool Connected
|
||||
{
|
||||
get => _connected;
|
||||
set
|
||||
{
|
||||
if (_connected == value) return;
|
||||
_connected = value;
|
||||
OnPropertyChanged(nameof(Connected));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("设备配置")]
|
||||
[DisplayName("PLC名称")]
|
||||
[Description("PLC设备名称")]
|
||||
public string PLCName
|
||||
{
|
||||
get => _plcName;
|
||||
set
|
||||
{
|
||||
if (_plcName == value) return;
|
||||
_plcName = value;
|
||||
OnPropertyChanged(nameof(PLCName));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("设备配置")]
|
||||
[DisplayName("PLC类型")]
|
||||
[Description("PLC通信协议类型")]
|
||||
public EnumPLCType PLCType
|
||||
{
|
||||
get => _plcType;
|
||||
set
|
||||
{
|
||||
if (_plcType == value) return;
|
||||
_plcType = value;
|
||||
OnPropertyChanged(nameof(PLCType));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("串口配置")]
|
||||
[DisplayName("COM端口")]
|
||||
[Description("串口号,如COM1")]
|
||||
public string COM
|
||||
{
|
||||
get => _com;
|
||||
set
|
||||
{
|
||||
if (_com == value) return;
|
||||
_com = value;
|
||||
OnPropertyChanged(nameof(COM));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("串口配置")]
|
||||
[DisplayName("波特率")]
|
||||
[Description("串口通信波特率")]
|
||||
public int BaudRate
|
||||
{
|
||||
get => _baudRate;
|
||||
set
|
||||
{
|
||||
if (_baudRate == value) return;
|
||||
_baudRate = value;
|
||||
OnPropertyChanged(nameof(BaudRate));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("串口配置")]
|
||||
[DisplayName("数据位")]
|
||||
[Description("数据位长度(5/6/7/8)")]
|
||||
public int DataBit
|
||||
{
|
||||
get => _dataBit;
|
||||
set
|
||||
{
|
||||
if (_dataBit == value) return;
|
||||
_dataBit = value;
|
||||
OnPropertyChanged(nameof(DataBit));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("串口配置")]
|
||||
[DisplayName("停止位")]
|
||||
[Description("停止位设置")]
|
||||
public StopBits StopBit
|
||||
{
|
||||
get => _stopBit;
|
||||
set
|
||||
{
|
||||
if (_stopBit == value) return;
|
||||
_stopBit = value;
|
||||
OnPropertyChanged(nameof(StopBit));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("串口配置")]
|
||||
[DisplayName("校验位")]
|
||||
[Description("奇偶校验方式")]
|
||||
public Parity Parity
|
||||
{
|
||||
get => _parity;
|
||||
set
|
||||
{
|
||||
if (_parity == value) return;
|
||||
_parity = value;
|
||||
OnPropertyChanged(nameof(Parity));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("网络配置")]
|
||||
[DisplayName("IP地址")]
|
||||
[Description("PLC网络地址")]
|
||||
public string IP
|
||||
{
|
||||
get => _ip;
|
||||
set
|
||||
{
|
||||
if (_ip == value) return;
|
||||
_ip = value;
|
||||
OnPropertyChanged(nameof(IP));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("网络配置")]
|
||||
[DisplayName("端口号")]
|
||||
[Description("网络通信端口")]
|
||||
public int Port
|
||||
{
|
||||
get => _port;
|
||||
set
|
||||
{
|
||||
if (_port == value) return;
|
||||
_port = value;
|
||||
OnPropertyChanged(nameof(Port));
|
||||
}
|
||||
}
|
||||
|
||||
[Category("点位配置")]
|
||||
[DisplayName("点位配置")]
|
||||
[Description("点位配置")]
|
||||
public BindingList<PLCItem> PLCItemList
|
||||
{
|
||||
get => _PLCItemList;
|
||||
set
|
||||
{
|
||||
if (_PLCItemList == value) return;
|
||||
_PLCItemList = value;
|
||||
OnPropertyChanged(nameof(PLCItemList));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public virtual bool PLCConnect()
|
||||
{
|
||||
Connected = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool PLCDisConnect()
|
||||
{
|
||||
Connected = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual Int16 ReadInt16(string address) { return 0; }
|
||||
|
||||
public virtual Int32 ReadInt32(string address) { return 0; }
|
||||
|
||||
public virtual UInt16 ReadUInt16(string address) { return 0; }
|
||||
|
||||
public virtual UInt32 ReadUInt32(string address) { return 0; }
|
||||
public virtual float ReadFloat(string address) { return 0; }
|
||||
public virtual bool ReadBool(string address) { return false; }
|
||||
|
||||
public virtual bool WriteInt16(string address, Int16 value, bool waitForReply = true) { return false; }
|
||||
public virtual bool WriteInt32(string address, Int32 value, bool waitForReply = true) { return false; }
|
||||
|
||||
|
||||
public virtual bool WriteUInt16(string address, UInt16 value, bool waitForReply = true) { return false; }
|
||||
public virtual bool WriteUInt32(string address, UInt32 value, bool waitForReply = true) { return false; }
|
||||
|
||||
public virtual bool WriteFloat(string address, float value, bool waitForReply = true) { return false; }
|
||||
public virtual bool WriteBool(string address, bool value, bool waitForReply = true) { return false; }
|
||||
}
|
||||
|
||||
|
||||
public class PLCItem : NotifyProperty
|
||||
{
|
||||
private bool _selected;
|
||||
private string _name = string.Empty;
|
||||
private EnumPLCDataType _type;
|
||||
private string _value = string.Empty;
|
||||
private bool _startexecute;
|
||||
private int _startindex;
|
||||
private string _address;
|
||||
/// <summary>
|
||||
/// 是否选中
|
||||
/// </summary>
|
||||
public bool Selected
|
||||
{
|
||||
get => _selected;
|
||||
set
|
||||
{
|
||||
if (_selected != value)
|
||||
{
|
||||
_selected = value;
|
||||
OnPropertyChanged(nameof(Selected));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 参数名称
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get => _name;
|
||||
set
|
||||
{
|
||||
if (_name != value)
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(nameof(Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
public EnumPLCDataType Type
|
||||
{
|
||||
get => _type;
|
||||
set
|
||||
{
|
||||
if (_type != value)
|
||||
{
|
||||
_type = value;
|
||||
OnPropertyChanged(nameof(Type));
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 参数类型
|
||||
/// </summary>
|
||||
public string Address
|
||||
{
|
||||
get => _address;
|
||||
set
|
||||
{
|
||||
if (_address != value)
|
||||
{
|
||||
_address = value;
|
||||
OnPropertyChanged(nameof(Address));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 参数值
|
||||
/// </summary>
|
||||
public string Value
|
||||
{
|
||||
get => _value;
|
||||
set
|
||||
{
|
||||
if (_value != value)
|
||||
{
|
||||
_value = value;
|
||||
OnPropertyChanged(nameof(Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启用状态
|
||||
/// </summary>
|
||||
public bool StartExecute
|
||||
{
|
||||
get => _startexecute;
|
||||
set
|
||||
{
|
||||
if (_startexecute != value)
|
||||
{
|
||||
_startexecute = value;
|
||||
OnPropertyChanged(nameof(StartExecute));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 顺序
|
||||
/// </summary>
|
||||
public int StartIndex
|
||||
{
|
||||
get => _startindex;
|
||||
set
|
||||
{
|
||||
if (_startindex != value)
|
||||
{
|
||||
_startindex = value;
|
||||
OnPropertyChanged(nameof(StartIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private CellLink[] cellLinks;
|
||||
[JsonIgnore]
|
||||
public CellLink[] CellLinks
|
||||
{
|
||||
get { return cellLinks; }
|
||||
set
|
||||
{
|
||||
if (cellLinks == value) return;
|
||||
cellLinks = value;
|
||||
OnPropertyChanged(nameof(CellLinks));
|
||||
}
|
||||
}
|
||||
|
||||
//private CellTag[] cellTags;
|
||||
//[JsonIgnore]
|
||||
//public CellTag[] CellTags
|
||||
//{
|
||||
// get { return cellTags; }
|
||||
// set
|
||||
// {
|
||||
// if (cellTags == value) return;
|
||||
// cellTags = value;
|
||||
// OnPropertyChanged(nameof(CellTags));
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
}
|
78
DH.Commons/Base/VisionEngineBase.cs
Normal file
78
DH.Commons/Base/VisionEngineBase.cs
Normal file
@ -0,0 +1,78 @@
|
||||
using System.Collections;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using DH.Commons.Enums;
|
||||
using DH.Commons.Helper;
|
||||
using HalconDotNet;
|
||||
using OpenCvSharp;
|
||||
|
||||
|
||||
|
||||
namespace DH.Commons.Base
|
||||
{
|
||||
/// <summary>
|
||||
/// 视觉处理引擎:1.传统视觉 2.深度学习
|
||||
/// CV深度学习 四大领域
|
||||
/// Image Classification 图像分类:判别图中物体是什么,比如是猫还是狗;
|
||||
/// Semantic Segmentation 语义分割:对图像进行像素级分类,预测每个像素属于的类别,不区分个体;
|
||||
/// Object Detection 目标检测:寻找图像中的物体并进行定位;
|
||||
/// Instance Segmentation 实例分割:定位图中每个物体,并进行像素级标注,区分不同个体;
|
||||
/// </summary>
|
||||
public abstract class VisionEngineBase : DeviceBase
|
||||
{
|
||||
public List<DetectionConfig> DetectionConfigs = new List<DetectionConfig>();
|
||||
#region event
|
||||
public event Action<string, List<double>> OnCropParamsOutput;
|
||||
public event Action<string, Bitmap, List<IShapeElement>> OnDetectionDone;
|
||||
public event Action<string> OnDetectionWarningStop;//有无检测 需要报警停机
|
||||
#endregion
|
||||
//public VisionEngineInitialConfigBase IConfig
|
||||
//{
|
||||
// get => InitialConfig as VisionEngineInitialConfigBase;
|
||||
//}
|
||||
// public ImageSaveHelper ImageSaveHelper { get; set; } = new ImageSaveHelper();
|
||||
public string BatchNO { get; set; }
|
||||
|
||||
public HTuple hv_ModelID;
|
||||
|
||||
public abstract DetectStationResult RunInference(MatSet originImgSet, string detectionId = null);
|
||||
|
||||
//public abstract void SaveDetectResultAsync(DetectStationResult detectResult);
|
||||
|
||||
|
||||
|
||||
public virtual void DetectionDone(string detectionId, Bitmap image, List<IShapeElement> detectionResults)
|
||||
{
|
||||
OnDetectionDone?.Invoke(detectionId, image, detectionResults);
|
||||
}
|
||||
|
||||
public virtual void DetectionWarningStop(string detectionDes)
|
||||
{
|
||||
OnDetectionWarningStop?.Invoke(detectionDes);
|
||||
}
|
||||
public ImageSaveHelper ImageSaveHelper { get; set; } = new ImageSaveHelper();
|
||||
public virtual void SaveImageAsync(string fullname, Bitmap saveMap, ImageFormat imageFormat)
|
||||
{
|
||||
if (saveMap != null)
|
||||
{
|
||||
ImageSaveSet imageSaveSet = new ImageSaveSet()
|
||||
{
|
||||
FullName = fullname,
|
||||
SaveImage = saveMap.CopyBitmap(),
|
||||
ImageFormat = imageFormat.DeepSerializeClone()
|
||||
|
||||
};
|
||||
|
||||
ImageSaveHelper.ImageSaveAsync(imageSaveSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
80
DH.Commons/Base/VisualLocalization.cs
Normal file
80
DH.Commons/Base/VisualLocalization.cs
Normal file
@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace DH.Commons.Base
|
||||
{
|
||||
public class VisualLocalization
|
||||
{
|
||||
// 配置属性
|
||||
public string CameraName { get; set; }
|
||||
public string ModelPath { get; set; }
|
||||
public string ImgPath { get; set; }
|
||||
public string Threshold { get; set; }
|
||||
public string Direction { get; set; }
|
||||
public string Speed { get; set; }
|
||||
|
||||
public string MSpeed { get; set; }
|
||||
|
||||
// 配置文件路径
|
||||
private const string ConfigFile = "VisualConfigs.json";
|
||||
private static readonly object _fileLock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// 保存当前配置(存在则更新,不存在则新增)
|
||||
/// </summary>
|
||||
public void Save()
|
||||
{
|
||||
lock (_fileLock)
|
||||
{
|
||||
var list = LoadAll();
|
||||
var existing = list.FirstOrDefault(c => c.CameraName == CameraName);
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
// 更新现有配置
|
||||
existing.ModelPath = ModelPath;
|
||||
existing.ImgPath = ImgPath;
|
||||
existing.Threshold = Threshold;
|
||||
existing.Direction = Direction;
|
||||
existing.Speed = Speed;
|
||||
existing.MSpeed = MSpeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(this);
|
||||
}
|
||||
|
||||
SaveAll(list);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取全部配置列表
|
||||
/// </summary>
|
||||
public static List<VisualLocalization> LoadAll()
|
||||
{
|
||||
lock (_fileLock)
|
||||
{
|
||||
if (!File.Exists(ConfigFile)) return new List<VisualLocalization>();
|
||||
|
||||
var json = File.ReadAllText(ConfigFile);
|
||||
return JsonSerializer.Deserialize<List<VisualLocalization>>(json)
|
||||
?? new List<VisualLocalization>();
|
||||
}
|
||||
}
|
||||
|
||||
private static void SaveAll(List<VisualLocalization> list)
|
||||
{
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
IgnoreNullValues = true
|
||||
};
|
||||
|
||||
File.WriteAllText(ConfigFile, JsonSerializer.Serialize(list, options));
|
||||
}
|
||||
}
|
||||
}
|
@ -13,15 +13,23 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AntdUI" Version="1.8.9" />
|
||||
<PackageReference Include="hyjiacan.pinyin4net" Version="4.1.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="OpenCvSharp4" Version="4.10.0.20241108" />
|
||||
<PackageReference Include="OpenCvSharp4.Extensions" Version="4.10.0.20241108" />
|
||||
<PackageReference Include="OpenCvSharp4.runtime.win" Version="4.10.0.20241108" />
|
||||
<PackageReference Include="System.IO.Ports" Version="9.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="DVPCameraCS64">
|
||||
<HintPath>..\X64\Debug\DVPCameraCS64.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="halcondotnet">
|
||||
<HintPath>..\x64\Debug\halcondotnet.dll</HintPath>
|
||||
</Reference>
|
||||
|
@ -1,16 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DH.Commons.Enums
|
||||
{
|
||||
public class CameraInfo
|
||||
{
|
||||
public string CamName { get; set; }
|
||||
public string Serinum { get; set; }
|
||||
public string IP { get; set; }
|
||||
}
|
||||
|
||||
}
|
@ -7,12 +7,62 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace DH.Commons.Enums
|
||||
{
|
||||
public enum EnumStatus
|
||||
{
|
||||
待机中,
|
||||
运行中,
|
||||
清料中,
|
||||
警告,
|
||||
异常
|
||||
}
|
||||
public enum ModelType
|
||||
{
|
||||
图像分类 = 1,
|
||||
目标检测 = 2,
|
||||
语义分割 = 3,
|
||||
实例分割 = 4,
|
||||
目标检测GPU = 5
|
||||
}
|
||||
public enum SelectPicType
|
||||
{
|
||||
[Description("训练图片")]
|
||||
train = 0,
|
||||
[Description("测试图片")]
|
||||
test
|
||||
|
||||
}
|
||||
public enum NetModel
|
||||
{
|
||||
[Description("目标检测")]
|
||||
training = 0,
|
||||
[Description("语义分割")]
|
||||
train_seg,
|
||||
[Description("模型导出")]
|
||||
emport,
|
||||
[Description("推理预测")]
|
||||
infernce
|
||||
|
||||
}
|
||||
public enum EnumCamType
|
||||
{
|
||||
[Description("度申相机")]
|
||||
度申Do3think = 0,
|
||||
[Description("海康相机")]
|
||||
海康hik ,
|
||||
|
||||
}
|
||||
|
||||
|
||||
public enum EnumPLCType
|
||||
{
|
||||
信捷XC_串口,
|
||||
信捷XC_网口,
|
||||
信捷XD_串口,
|
||||
信捷XD_网口
|
||||
[Description("信捷XC串口")]
|
||||
信捷XC串口 = 0,
|
||||
[Description("信捷XC网口")]
|
||||
信捷XC网口 = 1,
|
||||
[Description("信捷XD串口")]
|
||||
信捷XD串口 = 2,
|
||||
[Description("信捷XD网口")]
|
||||
信捷XD网口 = 3
|
||||
}
|
||||
|
||||
|
||||
@ -28,32 +78,84 @@ namespace DH.Commons.Enums
|
||||
public enum EnumPLCOutputIO
|
||||
{
|
||||
转盘方向=0,
|
||||
转盘速度=1,
|
||||
转盘使能=2,
|
||||
转盘启动=3,
|
||||
转盘清料=4,
|
||||
指示灯绿=5,
|
||||
指示灯黄=6,
|
||||
指示灯红=7,
|
||||
蜂鸣器=8,
|
||||
振动盘=9,
|
||||
皮带=10,
|
||||
工位1=11,
|
||||
工位2=12,
|
||||
工位3=13,
|
||||
工位4=14,
|
||||
工位5=15,
|
||||
OK料盒=16,
|
||||
NG料盒=17,
|
||||
OK吹气时间=18,
|
||||
NG吹气时间=19,
|
||||
产品计数=20,
|
||||
计数清零=21,
|
||||
工件最小值=22,
|
||||
工具最大值=23,
|
||||
启用心跳=24,
|
||||
心跳=25
|
||||
转盘速度,
|
||||
转盘使能,
|
||||
转盘启动,
|
||||
转盘清料,
|
||||
指示灯绿,
|
||||
指示灯黄,
|
||||
指示灯红,
|
||||
蜂鸣器,
|
||||
振动盘,
|
||||
皮带,
|
||||
工位1,
|
||||
工位2,
|
||||
工位3,
|
||||
工位4,
|
||||
工位5,
|
||||
工位6 ,
|
||||
工位7 ,
|
||||
工位8 ,
|
||||
工位9 ,
|
||||
工位10 ,
|
||||
相机触发时间,
|
||||
吹气时间,
|
||||
产品计数,
|
||||
计数清零,
|
||||
工件最小值,
|
||||
工件最大值,
|
||||
启用心跳,
|
||||
心跳地址,
|
||||
挡料电机回原点,
|
||||
挡料电机回原点速度,
|
||||
挡料电机速度,
|
||||
挡料电机顺时针,
|
||||
挡料电机逆时针,
|
||||
挡料电机位置,
|
||||
OK脉冲,
|
||||
NG脉冲,
|
||||
状态复位,
|
||||
启用定位,
|
||||
定位完成脉冲值,
|
||||
相机步进原点,
|
||||
相机步进位置,
|
||||
相机步进速度,
|
||||
相机步进顺时针,
|
||||
相机步进逆时针,
|
||||
点动相机步进,
|
||||
点动挡杆步进,
|
||||
相机步进实时位置,
|
||||
挡料电机实时位置
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public enum EnumPLCDataType
|
||||
{
|
||||
单字整型,
|
||||
双字整型,
|
||||
浮点型,
|
||||
布尔型
|
||||
}
|
||||
|
||||
public enum EnumBool
|
||||
{
|
||||
关闭,
|
||||
启用
|
||||
}
|
||||
public enum EnumBool1
|
||||
{
|
||||
False,
|
||||
True
|
||||
}
|
||||
|
||||
public enum EnumDetectionType
|
||||
{
|
||||
深度学习,
|
||||
尺寸测量
|
||||
}
|
||||
|
||||
|
||||
|
64
DH.Commons/Exception/ExceptionHelper.cs
Normal file
64
DH.Commons/Exception/ExceptionHelper.cs
Normal file
@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using static DH.Commons.Enums.EnumHelper;
|
||||
|
||||
|
||||
namespace DH.Commons.Helper
|
||||
{
|
||||
public enum ExceptionLevel
|
||||
{
|
||||
Info = 0,
|
||||
Warning = 1,
|
||||
Fatal = 2,
|
||||
}
|
||||
|
||||
//public delegate void OnProcessExceptionRaisedDelegate(DateTime dt, ProcessException ex);
|
||||
//[Serializable]
|
||||
public class ProcessException : Exception
|
||||
{
|
||||
public ExceptionLevel Level { get; set; } = ExceptionLevel.Warning;
|
||||
|
||||
public ProcessException()
|
||||
{
|
||||
}
|
||||
|
||||
public ProcessException(Exception ex, ExceptionLevel lvl = ExceptionLevel.Warning) : base(ex.Message, ex)
|
||||
{
|
||||
Level = lvl;
|
||||
ExceptionNotice();
|
||||
}
|
||||
|
||||
public ProcessException(string error, Exception ex = null, ExceptionLevel lvl = ExceptionLevel.Warning) : base(error, ex)
|
||||
{
|
||||
Level = lvl;
|
||||
ExceptionNotice();
|
||||
}
|
||||
|
||||
public void ExceptionNotice()
|
||||
{
|
||||
//OnProcessExceptionRaised?.Invoke(DateTime.Now, this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ExceptionHelper
|
||||
{
|
||||
public static LogLevel LogLevel = LogLevel.Information;
|
||||
public static string GetExceptionMessage(this Exception ex)
|
||||
{
|
||||
string msg = "异常信息:" + ex.Message;
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
msg += ";\t内部异常信息:" + ex.InnerException.GetExceptionMessage();
|
||||
}
|
||||
|
||||
if (LogLevel <= LogLevel.Assist)
|
||||
{
|
||||
msg += (";\r\n\t\tStackTrace:" + ex.StackTrace);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
||||
public class AuthorityException : ProcessException
|
||||
{
|
||||
}
|
||||
}
|
162
DH.Commons/Helper/AttributeHelper.cs
Normal file
162
DH.Commons/Helper/AttributeHelper.cs
Normal file
@ -0,0 +1,162 @@
|
||||
using DH.Commons.Enums;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using static DH.Commons.Enums.EnumHelper;
|
||||
|
||||
|
||||
namespace DH.Commons.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// 设备特性,指示该信息的设备类型,适用于设备信息和配置信息
|
||||
/// </summary>
|
||||
public class DeviceAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 设备类型
|
||||
/// </summary>
|
||||
public string TypeCode { get; set; }
|
||||
|
||||
public string TypeDescription { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 特性修饰类别
|
||||
/// </summary>
|
||||
public DeviceAttributeType AttrType { get; set; }
|
||||
|
||||
public DeviceAttribute(string typeCode, string typeDesc, EnumHelper.DeviceAttributeType attrType)
|
||||
{
|
||||
TypeCode = typeCode;
|
||||
TypeDescription = typeDesc;
|
||||
AttrType = attrType;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 预置状态特性 指定该修饰信息的前置状态允许范围
|
||||
/// </summary>
|
||||
public class PreStateAttribute : Attribute
|
||||
{
|
||||
public int PreState { get; set; }
|
||||
public PreStateAttribute(int _preState)
|
||||
{
|
||||
PreState = _preState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查当前待执行操作的前置状态要求是否合法
|
||||
/// </summary>
|
||||
/// <param name="currentState"></param>
|
||||
/// <returns></returns>
|
||||
public bool CheckPreStateValid(int currentState)
|
||||
{
|
||||
return (currentState & PreState) == currentState;
|
||||
}
|
||||
}
|
||||
|
||||
public class ColorSelectAttribute : Attribute
|
||||
{
|
||||
public string SelectedColor { get; set; }
|
||||
public ColorSelectAttribute(string selectedColor)
|
||||
{
|
||||
SelectedColor = selectedColor;
|
||||
}
|
||||
}
|
||||
|
||||
public class FontColorSelectAttribute : Attribute
|
||||
{
|
||||
public string SelectedColor { get; set; }
|
||||
public FontColorSelectAttribute(string selectedColor)
|
||||
{
|
||||
SelectedColor = selectedColor;
|
||||
}
|
||||
}
|
||||
|
||||
public enum InvokeType
|
||||
{
|
||||
/// <summary>
|
||||
/// 不公开调用
|
||||
/// </summary>
|
||||
[Description("不公开调用")]
|
||||
NoneInvoke = 0,
|
||||
/// <summary>
|
||||
/// 测试调用
|
||||
/// </summary>
|
||||
[Description("测试调用")]
|
||||
TestInvoke = 1,
|
||||
/// <summary>
|
||||
/// 标定调用
|
||||
/// </summary>
|
||||
[Description("标定调用")]
|
||||
CalibInvoke = 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用来修饰对外开放的调用方法的特性
|
||||
/// 调用方法参数顺序:IOperationConfig,InvokeDevice,SourceDevice
|
||||
/// </summary>
|
||||
public class ProcessMethodAttribute : Attribute
|
||||
{
|
||||
public string MethodCode { get; set; }
|
||||
public string MethodDesc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否提供人工调用测试
|
||||
/// </summary>
|
||||
public InvokeType InvokeType { get; set; }
|
||||
|
||||
public string DeviceType { get; set; }
|
||||
|
||||
public ProcessMethodAttribute(string deviceType, string code, string description, InvokeType invokeType)
|
||||
{
|
||||
DeviceType = deviceType;
|
||||
MethodCode = code;
|
||||
MethodDesc = description;
|
||||
InvokeType = invokeType;
|
||||
}
|
||||
}
|
||||
|
||||
public class SwitchDisplayAttribute : Attribute
|
||||
{
|
||||
public string SwitchName { get; set; }
|
||||
|
||||
public bool SwithOnStatus { get; set; } = true;
|
||||
|
||||
public SwitchDisplayAttribute(string name, bool status)
|
||||
{
|
||||
SwitchName = name;
|
||||
SwithOnStatus = status;
|
||||
}
|
||||
}
|
||||
|
||||
public class ElementAttribute : Attribute
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Desc { get; set; }
|
||||
|
||||
public string IconPath { get; set; }
|
||||
|
||||
public bool IsShowInToolBar { get; set; }
|
||||
|
||||
public ElementAttribute(string desc, string iconPath, bool isShowInToolBar = true, [CallerMemberName] string name = "")
|
||||
{
|
||||
Name = name;
|
||||
Desc = desc;
|
||||
IconPath = iconPath;
|
||||
IsShowInToolBar = isShowInToolBar;
|
||||
}
|
||||
}
|
||||
|
||||
public class ProcessAttribute : Attribute
|
||||
{
|
||||
public string ProcessCode { get; set; }
|
||||
public DeviceAttributeType AttrType { get; set; }
|
||||
|
||||
public ProcessAttribute(string stationCode, DeviceAttributeType attrType)
|
||||
{
|
||||
ProcessCode = stationCode;
|
||||
AttrType = attrType;
|
||||
}
|
||||
}
|
||||
}
|
280
DH.Commons/Helper/ConfigHelper.cs
Normal file
280
DH.Commons/Helper/ConfigHelper.cs
Normal file
@ -0,0 +1,280 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using AntdUI;
|
||||
using DH.Commons.Base;
|
||||
using DH.Commons.Enums;
|
||||
using DH.Commons.Models;
|
||||
|
||||
namespace DH.Commons.Helper
|
||||
{
|
||||
public static class ConfigHelper
|
||||
{
|
||||
private static readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
IgnoreNullValues = true
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 配置存储根目录
|
||||
/// </summary>
|
||||
private static string ConfigsRoot => Path.Combine(
|
||||
AppDomain.CurrentDomain.BaseDirectory,
|
||||
"configs");
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前方案的主配置文件路径
|
||||
/// </summary>
|
||||
private static string CurrentConfigPath
|
||||
{
|
||||
get
|
||||
{
|
||||
ValidateCurrentScheme();
|
||||
return Path.Combine(
|
||||
ConfigsRoot,
|
||||
$"config_{SystemModel.CurrentScheme}.json");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前方案的备份目录路径
|
||||
/// </summary>
|
||||
private static string CurrentBackupDir
|
||||
{
|
||||
get
|
||||
{
|
||||
ValidateCurrentScheme();
|
||||
return Path.Combine(
|
||||
ConfigsRoot,
|
||||
$"bak_{SystemModel.CurrentScheme}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化新方案(创建空文件)
|
||||
/// </summary>
|
||||
public static void InitializeScheme(string scheme)
|
||||
{
|
||||
SystemModel.CurrentScheme = scheme;
|
||||
|
||||
// 创建空配置文件
|
||||
if (!File.Exists(CurrentConfigPath))
|
||||
{
|
||||
Directory.CreateDirectory(ConfigsRoot);
|
||||
File.WriteAllText(CurrentConfigPath, "{}");
|
||||
}
|
||||
|
||||
// 创建备份目录
|
||||
Directory.CreateDirectory(CurrentBackupDir);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存当前配置(自动备份)
|
||||
/// </summary>
|
||||
public static void SaveConfig()
|
||||
{
|
||||
ValidateCurrentScheme();
|
||||
|
||||
// 确保配置目录存在
|
||||
Directory.CreateDirectory(ConfigsRoot);
|
||||
|
||||
// 备份现有配置
|
||||
if (File.Exists(CurrentConfigPath))
|
||||
{
|
||||
var backupName = $"config_{SystemModel.CurrentScheme}_{DateTime.Now:yyyyMMddHHmmss}.json";
|
||||
var backupPath = Path.Combine(CurrentBackupDir, backupName);
|
||||
|
||||
Directory.CreateDirectory(CurrentBackupDir);
|
||||
File.Copy(CurrentConfigPath, backupPath);
|
||||
}
|
||||
//重置标签文件路径和内容
|
||||
ConfigModel.DetectionList.ForEach(config =>
|
||||
{
|
||||
GenerateLabelFile(config);
|
||||
});
|
||||
|
||||
// 序列化当前配置
|
||||
var json = JsonSerializer.Serialize(new
|
||||
{
|
||||
ConfigModel.CameraBaseList,
|
||||
ConfigModel.PLCBaseList,
|
||||
ConfigModel.DetectionList,
|
||||
ConfigModel.GlobalList,
|
||||
}, _jsonOptions);
|
||||
|
||||
// 写入新配置
|
||||
File.WriteAllText(CurrentConfigPath, json);
|
||||
}
|
||||
private static void GenerateLabelFile(DetectionConfig config)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (config.DetectionLableList == null || string.IsNullOrEmpty(config.In_lable_path))
|
||||
return;
|
||||
|
||||
// 确保目录存在
|
||||
var directory = Path.GetDirectoryName(config.In_lable_path);
|
||||
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
// 写入文件内容
|
||||
using (var writer = new StreamWriter(config.In_lable_path, false))
|
||||
{
|
||||
foreach (var label in config.DetectionLableList)
|
||||
{
|
||||
//是否假如判断标签为中文转为为英文
|
||||
//string pinyinlabel = FileHelper.ConvertHanzitoPinyinWithNumbers(label.LabelName.ToString());
|
||||
//if (FileHelper.IsAlphaNumericOnly(pinyinlabel))
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
// 根据实际需求格式化输出
|
||||
writer.WriteLine(label.LabelName.ToString()); // 假设DetectionLable重写了ToString()
|
||||
|
||||
// 或者明确指定格式:
|
||||
// writer.WriteLine($"{label.Id},{label.Name},{label.Confidence}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"生成标签文件失败: {ex.Message}");
|
||||
// 可以考虑记录更详细的日志
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 加载当前方案配置
|
||||
/// </summary>
|
||||
public static void LoadConfig()
|
||||
{
|
||||
ValidateCurrentScheme();
|
||||
|
||||
if (!File.Exists(CurrentConfigPath))
|
||||
{
|
||||
InitializeScheme(SystemModel.CurrentScheme);
|
||||
return;
|
||||
}
|
||||
|
||||
var json = File.ReadAllText(CurrentConfigPath);
|
||||
var data = JsonSerializer.Deserialize<ConfigData>(json, _jsonOptions);
|
||||
|
||||
ConfigModel.CameraBaseList = data?.Cameras ?? new List<CameraBase>();
|
||||
ConfigModel.DetectionList = data?.Detections ?? new List<DetectionConfig>();
|
||||
ConfigModel.PLCBaseList = data?.PLCs ?? new List<PLCBase>();
|
||||
ConfigModel.GlobalList = data?.GlobalConfigs ?? new List<GlobalConfig>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证当前方案有效性
|
||||
/// </summary>
|
||||
private static void ValidateCurrentScheme()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(SystemModel.CurrentScheme))
|
||||
throw new InvalidOperationException("当前方案未设置");
|
||||
}
|
||||
/// <summary>
|
||||
/// 派生新方案(基于当前方案创建副本)
|
||||
/// </summary>
|
||||
/// <param name="newSchemeName">新方案名称</param>
|
||||
public static void DeriveScheme(string newSchemeName)
|
||||
{
|
||||
// 验证输入
|
||||
if (string.IsNullOrWhiteSpace(newSchemeName))
|
||||
{
|
||||
throw new ArgumentException("新方案名称不能为空");
|
||||
}
|
||||
|
||||
// 验证当前方案是否有效
|
||||
ValidateCurrentScheme();
|
||||
|
||||
// 检查新方案是否已存在
|
||||
var newConfigPath = Path.Combine(ConfigsRoot, $"config_{newSchemeName}.json");
|
||||
if (File.Exists(newConfigPath))
|
||||
{
|
||||
throw new InvalidOperationException($"方案 {newSchemeName} 已存在");
|
||||
}
|
||||
|
||||
// 保存当前配置确保最新
|
||||
SaveConfig();
|
||||
|
||||
try
|
||||
{
|
||||
// 复制配置文件
|
||||
File.Copy(CurrentConfigPath, newConfigPath);
|
||||
|
||||
// 创建备份目录
|
||||
var newBackupDir = Path.Combine(ConfigsRoot, $"bak_{newSchemeName}");
|
||||
Directory.CreateDirectory(newBackupDir);
|
||||
|
||||
// 可选:自动切换新方案
|
||||
// SystemModel.CurrentScheme = newSchemeName;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
throw new InvalidOperationException($"方案派生失败: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除指定方案的配置文件及备份目录
|
||||
/// </summary>
|
||||
/// <param name="schemeName">要删除的方案名称</param>
|
||||
/// <exception cref="ArgumentException">当方案名称为空时抛出</exception>
|
||||
/// <exception cref="IOException">文件操作失败时抛出</exception>
|
||||
public static void DeleteSchemeConfig(string schemeName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(schemeName))
|
||||
throw new ArgumentException("方案名称无效");
|
||||
|
||||
// 构造路径
|
||||
var configPath = Path.Combine(ConfigsRoot, $"config_{schemeName}.json");
|
||||
var backupDir = Path.Combine(ConfigsRoot, $"bak_{schemeName}");
|
||||
|
||||
try
|
||||
{
|
||||
// 删除配置文件
|
||||
if (File.Exists(configPath))
|
||||
{
|
||||
File.Delete(configPath);
|
||||
}
|
||||
|
||||
// 删除备份目录(递归删除)
|
||||
if (Directory.Exists(backupDir))
|
||||
{
|
||||
Directory.Delete(backupDir, true);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException)
|
||||
{
|
||||
throw new IOException($"删除方案 {schemeName} 的配置文件失败: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 配置数据模型(内部类)
|
||||
/// </summary>
|
||||
private class ConfigData
|
||||
{
|
||||
[JsonPropertyName("cameraBaseList")]
|
||||
public List<CameraBase> Cameras { get; set; } = new List<CameraBase>();
|
||||
|
||||
[JsonPropertyName("plcBaseList")]
|
||||
public List<PLCBase> PLCs { get; set; } = new List<PLCBase>();
|
||||
|
||||
[JsonPropertyName("detectionList")]
|
||||
public List<DetectionConfig> Detections { get; set; } = new List<DetectionConfig>();
|
||||
[JsonPropertyName("globalList")]
|
||||
public List<GlobalConfig> GlobalConfigs { get; set; } = new List<GlobalConfig>();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -76,159 +76,83 @@ namespace DH.Commons.Enums
|
||||
}
|
||||
}
|
||||
|
||||
//public static System.Windows.Media.Color GetEnumSelectedMediaColor(this Enum enumObj)
|
||||
//{
|
||||
// Type t = enumObj.GetType();
|
||||
// FieldInfo f = t.GetField(enumObj.ToString());
|
||||
|
||||
// ColorSelectAttribute attr = f.GetCustomAttribute<ColorSelectAttribute>();
|
||||
// if (attr != null)
|
||||
// {
|
||||
// var prop = typeof(System.Windows.Media.Colors).GetProperties().FirstOrDefault(p => p.Name == attr.SelectedColor);
|
||||
// if (prop != null)
|
||||
// {
|
||||
// return (System.Windows.Media.Color)prop.GetValue(null);
|
||||
// }
|
||||
// }
|
||||
// return System.Windows.Media.Colors.Transparent;
|
||||
//}
|
||||
|
||||
//public static System.Drawing.Color GetEnumSelectedColor(this Enum enumObj)
|
||||
//{
|
||||
// Type t = enumObj.GetType();
|
||||
// FieldInfo f = t.GetField(enumObj.ToString());
|
||||
|
||||
// ColorSelectAttribute attr = f.GetCustomAttribute<ColorSelectAttribute>();
|
||||
// if (attr != null)
|
||||
// {
|
||||
// return System.Drawing.Color.FromName(attr.SelectedColor);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return System.Drawing.Color.Transparent;
|
||||
// }
|
||||
//}
|
||||
|
||||
//public static System.Drawing.Color GetEnumSelectedFontColor(this Enum enumObj)
|
||||
//{
|
||||
// Type t = enumObj.GetType();
|
||||
// FieldInfo f = t.GetField(enumObj.ToString());
|
||||
|
||||
// var attr = f.GetCustomAttribute<FontColorSelectAttribute>();
|
||||
// if (attr != null)
|
||||
// {
|
||||
// return System.Drawing.Color.FromName(attr.SelectedColor);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return System.Drawing.Color.Transparent;
|
||||
// }
|
||||
//}
|
||||
|
||||
//public static string GetEnumSelectedColorString(this Enum enumObj)
|
||||
//{
|
||||
// Type t = enumObj.GetType();
|
||||
// FieldInfo f = t.GetField(enumObj.ToString());
|
||||
|
||||
// ColorSelectAttribute attr = f.GetCustomAttribute<ColorSelectAttribute>();
|
||||
// if (attr != null)
|
||||
// {
|
||||
// return attr.SelectedColor;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return "Transparent";
|
||||
// }
|
||||
//}
|
||||
|
||||
// 根据描述获取枚举值(泛型方法)
|
||||
public static T GetEnumFromDescription<T>(string description) where T : Enum
|
||||
{
|
||||
Type enumType = typeof(T);
|
||||
foreach (T value in Enum.GetValues(enumType))
|
||||
{
|
||||
string desc = GetEnumDescription(value);
|
||||
if (desc == description)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
throw new ArgumentException($"在枚举 {enumType.Name} 中未找到描述为 '{description}' 的值");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当枚举牵涉到状态变换,检查现状态是否满足待转换的状态的前置状态要求
|
||||
/// 获取枚举类型的所有描述文本
|
||||
/// </summary>
|
||||
/// <param name="stateToBe"></param>
|
||||
/// <param name="currentState"></param>
|
||||
/// <returns></returns>
|
||||
//public static bool CheckPreStateValid(this Enum stateToBe, int currentState)
|
||||
//{
|
||||
// Type t = stateToBe.GetType();
|
||||
// FieldInfo f = t.GetField(stateToBe.ToString());
|
||||
/// <param name="enumType">枚举类型</param>
|
||||
/// <returns>描述文本列表</returns>
|
||||
public static List<string> GetEnumDescriptions(Type enumType)
|
||||
{
|
||||
// 验证类型是否为枚举
|
||||
if (!enumType.IsEnum)
|
||||
throw new ArgumentException("传入的类型必须是枚举类型", nameof(enumType));
|
||||
|
||||
// PreStateAttribute attr = f.GetCustomAttribute<PreStateAttribute>();
|
||||
// if (attr == null)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return attr.CheckPreStateValid(currentState);
|
||||
// }
|
||||
//}
|
||||
var descriptions = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// 设备状态定义
|
||||
/// 未初始化和异常状态无前置状态要求
|
||||
/// 初始化操作前置状态必须是未初始化、关闭状态和异常状态
|
||||
/// 打开前置必须是初始化和暂停
|
||||
/// 关闭前置必须是打开和暂停和异常
|
||||
/// 暂停前置必须是打开
|
||||
/// </summary>
|
||||
//public enum DeviceState
|
||||
//{
|
||||
// TBD = -1,
|
||||
foreach (var value in Enum.GetValues(enumType))
|
||||
{
|
||||
var fieldInfo = enumType.GetField(value.ToString());
|
||||
var attribute = fieldInfo.GetCustomAttribute<DescriptionAttribute>();
|
||||
descriptions.Add(attribute?.Description ?? value.ToString());
|
||||
}
|
||||
|
||||
// [ColorSelect("Gray")]
|
||||
// [FontColorSelect("Black")]
|
||||
// [Description("未初始化")]
|
||||
// DSUninit = 1,
|
||||
return descriptions;
|
||||
}
|
||||
public static string GetEnumDescription1(Enum value)
|
||||
{
|
||||
var field = value.GetType().GetField(value.ToString());
|
||||
var attribute = field.GetCustomAttributes(typeof(DescriptionAttribute), false)
|
||||
.FirstOrDefault() as DescriptionAttribute;
|
||||
return attribute?.Description ?? value.ToString();
|
||||
}
|
||||
|
||||
// [ColorSelect("Gold")]
|
||||
// [FontColorSelect("White")]
|
||||
// [PreState(1 + 2 + 4 + 8 + 32)]
|
||||
// [Description("初始化")]
|
||||
// DSInit = 2,
|
||||
public static System.Drawing.Color GetEnumSelectedColor(this Enum enumObj)
|
||||
{
|
||||
Type t = enumObj.GetType();
|
||||
FieldInfo f = t.GetField(enumObj.ToString());
|
||||
|
||||
// [ColorSelect("Lime")]
|
||||
// [FontColorSelect("Black")]
|
||||
// [PreState(2 + 4 + 16)]
|
||||
// [Description("运行中")]
|
||||
// DSOpen = 4,
|
||||
ColorSelectAttribute attr = f.GetCustomAttribute<ColorSelectAttribute>();
|
||||
if (attr != null)
|
||||
{
|
||||
return System.Drawing.Color.FromName(attr.SelectedColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
return System.Drawing.Color.Transparent;
|
||||
}
|
||||
}
|
||||
|
||||
// [ColorSelect("Gray")]
|
||||
// [FontColorSelect("White")]
|
||||
// [PreState(1 + 4 + 8 + 16 + 32)]
|
||||
// [Description("关闭")]
|
||||
// DSClose = 8,
|
||||
public static System.Drawing.Color GetEnumSelectedFontColor(this Enum enumObj)
|
||||
{
|
||||
Type t = enumObj.GetType();
|
||||
FieldInfo f = t.GetField(enumObj.ToString());
|
||||
|
||||
// [ColorSelect("Gold")]
|
||||
// [FontColorSelect("White")]
|
||||
// [PreState(4 + 16)]
|
||||
// [Description("暂停")]
|
||||
// DSPause = 16,
|
||||
var attr = f.GetCustomAttribute<FontColorSelectAttribute>();
|
||||
if (attr != null)
|
||||
{
|
||||
return System.Drawing.Color.FromName(attr.SelectedColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
return System.Drawing.Color.Transparent;
|
||||
}
|
||||
}
|
||||
|
||||
// [ColorSelect("Red")]
|
||||
// [FontColorSelect("White")]
|
||||
// [Description("异常")]
|
||||
// DSExcept = 32
|
||||
//}
|
||||
|
||||
///// <summary>
|
||||
///// 工序状态
|
||||
///// </summary>
|
||||
//public enum RunState
|
||||
//{
|
||||
// [ColorSelect("Gold")]
|
||||
// [Description("空闲")]
|
||||
// Idle = 1,
|
||||
// [ColorSelect("Lime")]
|
||||
// [Description("运行中")]
|
||||
// Running = 2,
|
||||
// [ColorSelect("Gray")]
|
||||
// [Description("停止")]
|
||||
// Stop = 3,
|
||||
// [ColorSelect("Red")]
|
||||
// [Description("宕机")]
|
||||
// Down = 99,
|
||||
//}
|
||||
|
||||
[Flags]
|
||||
public enum DeviceAttributeType
|
||||
@ -361,7 +285,38 @@ namespace DH.Commons.Enums
|
||||
[Description("测量结果")]
|
||||
MeasureResult = 31,
|
||||
}
|
||||
|
||||
|
||||
public enum LogLevel
|
||||
{
|
||||
[Description("详细")]
|
||||
[ColorSelect("White")]
|
||||
[FontColorSelect("Green")]
|
||||
Detail = 2,
|
||||
[Description("信息")]
|
||||
[ColorSelect("White")]
|
||||
[FontColorSelect("Dark")]
|
||||
Information = 3,
|
||||
[Description("辅助")]
|
||||
[ColorSelect("White")]
|
||||
[FontColorSelect("Blue")]
|
||||
Assist = 4,
|
||||
[Description("动作")]
|
||||
[ColorSelect("DarkGreen")]
|
||||
[FontColorSelect("Yellow")]
|
||||
Action = 5,
|
||||
[Description("错误")]
|
||||
[ColorSelect("Orange")]
|
||||
[FontColorSelect("White")]
|
||||
Error = 6,
|
||||
[Description("警报")]
|
||||
[ColorSelect("Brown")]
|
||||
[FontColorSelect("White")]
|
||||
Warning = 7,
|
||||
[Description("异常")]
|
||||
[ColorSelect("Red")]
|
||||
[FontColorSelect("White")]
|
||||
Exception = 8,
|
||||
}
|
||||
//public enum CameraDriverType
|
||||
//{
|
||||
// Halcon,
|
||||
@ -382,6 +337,59 @@ namespace DH.Commons.Enums
|
||||
// NG = -1,
|
||||
// IGNORE = -999,
|
||||
//}
|
||||
public enum DeviceState
|
||||
{
|
||||
TBD = -1,
|
||||
|
||||
[ColorSelect("Gray")]
|
||||
[FontColorSelect("Black")]
|
||||
[Description("未初始化")]
|
||||
DSUninit = 1,
|
||||
|
||||
[ColorSelect("Gold")]
|
||||
[FontColorSelect("White")]
|
||||
[PreState(1 + 2 + 4 + 8 + 32)]
|
||||
[Description("初始化")]
|
||||
DSInit = 2,
|
||||
|
||||
[ColorSelect("Lime")]
|
||||
[FontColorSelect("Black")]
|
||||
[PreState(2 + 4 + 16)]
|
||||
[Description("运行中")]
|
||||
DSOpen = 4,
|
||||
|
||||
[ColorSelect("Gray")]
|
||||
[FontColorSelect("White")]
|
||||
[PreState(1 + 4 + 8 + 16 + 32)]
|
||||
[Description("关闭")]
|
||||
DSClose = 8,
|
||||
|
||||
[ColorSelect("Gold")]
|
||||
[FontColorSelect("White")]
|
||||
[PreState(4 + 16)]
|
||||
[Description("暂停")]
|
||||
DSPause = 16,
|
||||
|
||||
[ColorSelect("Red")]
|
||||
[FontColorSelect("White")]
|
||||
[Description("异常")]
|
||||
DSExcept = 32
|
||||
}
|
||||
public enum RunState
|
||||
{
|
||||
[ColorSelect("Gold")]
|
||||
[Description("空闲")]
|
||||
Idle = 1,
|
||||
[ColorSelect("Lime")]
|
||||
[Description("运行中")]
|
||||
Running = 2,
|
||||
[ColorSelect("Gray")]
|
||||
[Description("停止")]
|
||||
Stop = 3,
|
||||
[ColorSelect("Red")]
|
||||
[Description("宕机")]
|
||||
Down = 99,
|
||||
}
|
||||
|
||||
public enum PriorityDirection
|
||||
{
|
||||
|
507
DH.Commons/Helper/FileHelper.cs
Normal file
507
DH.Commons/Helper/FileHelper.cs
Normal file
@ -0,0 +1,507 @@
|
||||
using hyjiacan.py4n;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DH.Commons.Enums
|
||||
{
|
||||
|
||||
public static class FileHelper
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 清理两个文件夹中的文件,保留文件名交集部分,其余文件删除。
|
||||
/// </summary>
|
||||
/// <param name="imagesFolder">图片文件夹路径</param>
|
||||
/// <param name="labelsFolder">标签文件夹路径</param>
|
||||
public static void CleanupFolders(string imagesFolder, string labelsFolder)
|
||||
{
|
||||
if (!Directory.Exists(imagesFolder))
|
||||
{
|
||||
Console.WriteLine($"Images folder does not exist: {imagesFolder}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(labelsFolder))
|
||||
{
|
||||
Console.WriteLine($"Labels folder does not exist: {labelsFolder}");
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取文件名(不包含扩展名)
|
||||
var imageFiles = Directory.GetFiles(imagesFolder)
|
||||
.Select(Path.GetFileNameWithoutExtension)
|
||||
.ToHashSet();
|
||||
|
||||
var labelFiles = Directory.GetFiles(labelsFolder)
|
||||
.Select(Path.GetFileNameWithoutExtension)
|
||||
.ToHashSet();
|
||||
|
||||
// 计算交集
|
||||
var commonFiles = imageFiles.Intersect(labelFiles);
|
||||
|
||||
// 删除 images 文件夹中不在交集中的文件
|
||||
foreach (var imagePath in Directory.GetFiles(imagesFolder))
|
||||
{
|
||||
string fileNameWithoutExt = Path.GetFileNameWithoutExtension(imagePath);
|
||||
if (!commonFiles.Contains(fileNameWithoutExt))
|
||||
{
|
||||
File.Delete(imagePath);
|
||||
Console.WriteLine($"Deleted image file: {imagePath}");
|
||||
}
|
||||
}
|
||||
|
||||
// 删除 labels 文件夹中不在交集中的文件
|
||||
foreach (var labelPath in Directory.GetFiles(labelsFolder))
|
||||
{
|
||||
string fileNameWithoutExt = Path.GetFileNameWithoutExtension(labelPath);
|
||||
if (!commonFiles.Contains(fileNameWithoutExt))
|
||||
{
|
||||
File.Delete(labelPath);
|
||||
Console.WriteLine($"Deleted label file: {labelPath}");
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("Folders cleaned successfully!");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取文件夹中所有图片文件的个数
|
||||
/// </summary>
|
||||
/// <param name="folderPath">目标文件夹路径</param>
|
||||
/// <param name="includeSubdirectories">是否包含子文件夹,默认不包含</param>
|
||||
/// <returns>图片文件总数</returns>
|
||||
public static int CountImageFiles(string folderPath, bool includeSubdirectories = false)
|
||||
{
|
||||
if (!Directory.Exists(folderPath))
|
||||
{
|
||||
throw new DirectoryNotFoundException($"The folder '{folderPath}' does not exist.");
|
||||
}
|
||||
|
||||
// 支持的图片格式
|
||||
string[] imageExtensions = { "*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif" };
|
||||
|
||||
// 搜索选项
|
||||
SearchOption searchOption = includeSubdirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
|
||||
|
||||
int fileCount = 0;
|
||||
|
||||
foreach (var ext in imageExtensions)
|
||||
{
|
||||
fileCount += Directory.GetFiles(folderPath, ext, searchOption).Length;
|
||||
}
|
||||
|
||||
return fileCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除一个目录所有子目录和文件
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
public static void DeleteDirectoryAndContents(string path)
|
||||
{
|
||||
// 确保目录存在
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
// 删除目录中的文件
|
||||
string[] files = Directory.GetFiles(path);
|
||||
foreach (var file in files)
|
||||
{
|
||||
File.Delete(file);
|
||||
Console.WriteLine($"文件已删除: {file}");
|
||||
}
|
||||
|
||||
// 删除目录中的子目录
|
||||
string[] directories = Directory.GetDirectories(path);
|
||||
foreach (var directory in directories)
|
||||
{
|
||||
DeleteDirectoryAndContents(directory); // 递归删除子目录
|
||||
}
|
||||
|
||||
// 删除空目录
|
||||
Directory.Delete(path);
|
||||
Console.WriteLine($"目录已删除: {path}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("目录不存在!");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 将一个文件夹中的所有图片文件和 JSON 文件复制到另一个文件夹中
|
||||
/// </summary>
|
||||
/// <param name="sourceDirectory"></param>
|
||||
/// <param name="destinationDirectory"></param>
|
||||
public static void CopyImageAndJsonFiles(string sourceDirectory, string destinationDirectory)
|
||||
{
|
||||
// 确保目标文件夹存在,如果不存在则创建它
|
||||
if (!Directory.Exists(destinationDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(destinationDirectory);
|
||||
}
|
||||
|
||||
// 获取源文件夹中的所有图片文件和 JSON 文件
|
||||
string[] imageFiles = Directory.GetFiles(sourceDirectory, "*.*")
|
||||
.Where(file => file.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) ||
|
||||
file.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase) ||
|
||||
file.EndsWith(".png", StringComparison.OrdinalIgnoreCase) ||
|
||||
file.EndsWith(".gif", StringComparison.OrdinalIgnoreCase) ||
|
||||
file.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase) ||
|
||||
file.EndsWith(".tiff", StringComparison.OrdinalIgnoreCase) ||
|
||||
file.EndsWith(".webp", StringComparison.OrdinalIgnoreCase))
|
||||
.ToArray();
|
||||
|
||||
string[] jsonFiles = Directory.GetFiles(sourceDirectory, "*.json");
|
||||
|
||||
// 合并图片文件和 JSON 文件
|
||||
string[] filesToCopy = imageFiles.Concat(jsonFiles).ToArray();
|
||||
|
||||
foreach (string file in filesToCopy)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 获取文件名
|
||||
string fileName = Path.GetFileName(file);
|
||||
|
||||
// 拼接目标文件的完整路径
|
||||
string destinationFile = Path.Combine(destinationDirectory, fileName);
|
||||
|
||||
// 如果目标文件已存在,可以选择覆盖或跳过(这里我们选择跳过)
|
||||
if (File.Exists(destinationFile))
|
||||
{
|
||||
Console.WriteLine($"文件 {fileName} 已存在,跳过复制.");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 复制文件
|
||||
File.Copy(file, destinationFile);
|
||||
Console.WriteLine($"文件 {fileName} 已成功复制到 {destinationDirectory}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"复制文件 {file} 时出错: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 遍历图片文件夹,检查对应的标签文件夹中是否有同名的 .txt 文件。
|
||||
/// 如果没有,则创建一个空的 .txt 文件。
|
||||
/// </summary>
|
||||
/// <param name="imagesDirectory">图片文件夹路径</param>
|
||||
/// <param name="labelsDirectory">标签文件夹路径</param>
|
||||
public static void ProcessImageFiles(string imagesDirectory, string labelsDirectory)
|
||||
{
|
||||
// 检查 images 目录是否存在
|
||||
if (!Directory.Exists(imagesDirectory))
|
||||
{
|
||||
throw new DirectoryNotFoundException($"目录 {imagesDirectory} 不存在.");
|
||||
}
|
||||
|
||||
// 检查 labels 目录是否存在,如果不存在则创建
|
||||
if (!Directory.Exists(labelsDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(labelsDirectory);
|
||||
Console.WriteLine($"目录 {labelsDirectory} 已创建.");
|
||||
}
|
||||
|
||||
// 获取 images 目录中的所有文件(包括图片文件)
|
||||
string[] imageFiles = Directory.GetFiles(imagesDirectory, "*.*", SearchOption.TopDirectoryOnly);
|
||||
string[] validExtensions = { ".jpg", ".jpeg", ".png", ".bmp", ".gif" }; // 支持的图片格式
|
||||
|
||||
foreach (var imageFile in imageFiles)
|
||||
{
|
||||
// 检查文件扩展名是否为支持的图片格式
|
||||
string extension = Path.GetExtension(imageFile).ToLower();
|
||||
if (Array.Exists(validExtensions, ext => ext == extension))
|
||||
{
|
||||
// 获取图片文件的文件名(不包括扩展名)
|
||||
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(imageFile);
|
||||
|
||||
// 生成对应的 txt 文件路径
|
||||
string labelFilePath = Path.Combine(labelsDirectory, fileNameWithoutExtension + ".txt");
|
||||
|
||||
// 如果该 txt 文件不存在,则创建一个空白 txt 文件
|
||||
if (!File.Exists(labelFilePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
File.WriteAllText(labelFilePath, string.Empty); // 创建空白 txt 文件
|
||||
Console.WriteLine($"创建空白文件: {labelFilePath}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"无法创建文件 {labelFilePath}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 封装的函数:删除没有对应 JSON 文件的图片
|
||||
public static void DeleteUnmatchedImages(string labelsFolderPath, string imagesFolderPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 获取 labels 文件夹中的所有 JSON 文件名(去除扩展名)
|
||||
string[] jsonFiles = Directory.GetFiles(labelsFolderPath, "*.txt");
|
||||
HashSet<string> jsonFileNames = new HashSet<string>();
|
||||
|
||||
foreach (string jsonFile in jsonFiles)
|
||||
{
|
||||
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(jsonFile);
|
||||
jsonFileNames.Add(fileNameWithoutExtension);
|
||||
}
|
||||
|
||||
// 获取 images 文件夹中的所有图片文件
|
||||
string[] imageFiles = Directory.GetFiles(imagesFolderPath);
|
||||
|
||||
// 遍历图片文件,检查是否有对应的 JSON 文件
|
||||
foreach (string imageFile in imageFiles)
|
||||
{
|
||||
string imageFileNameWithoutExtension = Path.GetFileNameWithoutExtension(imageFile);
|
||||
|
||||
// 如果图片文件名不在 labels 文件夹的 JSON 文件名集合中,则删除该图片
|
||||
if (!jsonFileNames.Contains(imageFileNameWithoutExtension))
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(imageFile); // 删除图片
|
||||
Console.WriteLine($"已删除图片: {Path.GetFileName(imageFile)}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"删除文件 {Path.GetFileName(imageFile)} 时出错: {ex.Message}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"图片 {Path.GetFileName(imageFile)} 有对应的 JSON 文件,不删除。");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"操作失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 List<string> 保存到指定文件中,格式为 "项,标签"。
|
||||
/// 标签是根据项的索引生成的。
|
||||
/// </summary>
|
||||
/// <param name="items">要保存的字符串列表</param>
|
||||
/// <param name="filePath">保存文件的路径</param>
|
||||
public static void SaveItemsToFile(List<string> items, string filePath)
|
||||
{
|
||||
// 使用 StreamWriter 写入文件
|
||||
using (StreamWriter writer = new StreamWriter(filePath))
|
||||
{
|
||||
// 遍历 items 列表
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
{
|
||||
// 写入每一行,格式为 "项, 标签"
|
||||
writer.WriteLine($"{items[i]},{i}");
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void SaveItemsToFile(HashSet<string> items, string filePath)
|
||||
{
|
||||
// 使用 StreamWriter 写入文件
|
||||
using (StreamWriter writer = new StreamWriter(filePath))
|
||||
{
|
||||
// 遍历 HashSet
|
||||
int i = 0;
|
||||
foreach (string item in items)
|
||||
{
|
||||
// 写入每一行,格式为 "项, 标签"
|
||||
writer.WriteLine($"{item},{i}"); // 假设使用 item 的长度作为标签
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
static List<FileInformation> FileList = new List<FileInformation>();
|
||||
|
||||
/// <summary>
|
||||
/// 递归获取指定文件夹下所有文件
|
||||
/// </summary>
|
||||
/// <param name="dir"></param>
|
||||
/// <returns></returns>
|
||||
public static List<FileInformation> GetAllFiles(DirectoryInfo dir)
|
||||
{
|
||||
FileInfo[] allFile = dir.GetFiles();
|
||||
foreach (FileInfo fi in allFile)
|
||||
{
|
||||
FileList.Add(new FileInformation { FileName = fi.Name, FilePath = fi.FullName });
|
||||
}
|
||||
DirectoryInfo[] allDir = dir.GetDirectories();
|
||||
foreach (DirectoryInfo d in allDir)
|
||||
{
|
||||
GetAllFiles(d);
|
||||
}
|
||||
return FileList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断字符串是否纯字母
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsAlphabetOnly(string input)
|
||||
{
|
||||
return Regex.IsMatch(input, "^[a-zA-Z]+$");
|
||||
}
|
||||
/// <summary>
|
||||
/// 判断字符串是否仅包含大小写字母和数字
|
||||
/// </summary>
|
||||
/// <param name="input">待判断的字符串</param>
|
||||
/// <returns>如果字符串仅包含字母和数字,返回 true;否则返回 false</returns>
|
||||
public static bool IsAlphaNumericOnly(string input)
|
||||
{
|
||||
return Regex.IsMatch(input, "^[a-zA-Z0-9]+$");
|
||||
}
|
||||
public static string ConvertHanzitoPinyinWithNumbers(string input)
|
||||
{
|
||||
// 正则表达式匹配汉字
|
||||
string pattern = @"[\u4e00-\u9fa5]";
|
||||
Regex regex = new Regex(pattern);
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
int lastIndex = 0;
|
||||
|
||||
foreach (Match match in regex.Matches(input))
|
||||
{
|
||||
// 将非汉字部分保留为原样
|
||||
result.Append(input.Substring(lastIndex, match.Index - lastIndex));
|
||||
|
||||
// 获取汉字并转换为拼音
|
||||
string hanzi = match.Value;
|
||||
string pinyin = ConvertHanziToPinyin(hanzi);
|
||||
|
||||
// 将拼音追加到结果中
|
||||
result.Append(pinyin);
|
||||
|
||||
lastIndex = match.Index + match.Length;
|
||||
}
|
||||
|
||||
// 添加最后的非汉字部分
|
||||
result.Append(input.Substring(lastIndex));
|
||||
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
public static string ConvertHanziToPinyin(string hanzi)
|
||||
{
|
||||
// 设置拼音格式:去掉音调,拼音小写,ü保持为u:
|
||||
PinyinFormat format = PinyinFormat.WITHOUT_TONE | PinyinFormat.LOWERCASE | PinyinFormat.WITH_U_AND_COLON;
|
||||
|
||||
// 获取拼音数组
|
||||
List<PinyinItem> pinyinItems = Pinyin4Net.GetPinyinArray(hanzi, format);
|
||||
|
||||
StringBuilder pinyinBuilder = new StringBuilder();
|
||||
|
||||
foreach (var item in pinyinItems)
|
||||
{
|
||||
// 处理多音字:默认取第一个拼音
|
||||
if (item.Count > 0)
|
||||
{
|
||||
string pinyin = item[0];
|
||||
|
||||
// 特殊处理ü的情况
|
||||
pinyin = pinyin.Replace("u:", "v"); // 将u:转为v,这是常见的拼音表示法
|
||||
|
||||
pinyinBuilder.Append(pinyin);
|
||||
}
|
||||
}
|
||||
|
||||
return pinyinBuilder.ToString();
|
||||
}
|
||||
/// <summary>
|
||||
/// 汉字拼音转化
|
||||
/// </summary>
|
||||
/// <param name="hanzi"></param>
|
||||
/// <returns></returns>
|
||||
//public static string ConvertHanzitoPinyin(string hanzi)
|
||||
//{
|
||||
// PinyinFormat format = PinyinFormat.WITHOUT_TONE | PinyinFormat.LOWERCASE | PinyinFormat.WITH_U_UNICODE;
|
||||
|
||||
// // string hanzi = defectRow.LabelDescription;
|
||||
// List<PinyinItem> pylist = Pinyin4Net.GetPinyinArray(hanzi, format);
|
||||
// // 提取所有拼音并合并为一个字符串
|
||||
// List<string> pinyinStrings = new List<string>();
|
||||
// foreach (var item in pylist)
|
||||
// {
|
||||
// // 将PinyinItem中的每个拼音(List<string>)合并为一个字符串
|
||||
// string joinedPinyin = string.Join("", item); // 这里的item就是一个List<string>,其中存储了拼音
|
||||
// pinyinStrings.Add(joinedPinyin); // 添加合并后的拼音
|
||||
// }
|
||||
|
||||
// // 合并所有拼音为一个字符串
|
||||
// string allPinyin = string.Join("", pinyinStrings);
|
||||
// return allPinyin;
|
||||
//}
|
||||
/// <summary>
|
||||
/// 递归获取指定文件夹下所有文件
|
||||
/// </summary>
|
||||
/// <param name="dir"></param>
|
||||
/// <returns></returns>
|
||||
public static List<FileInformation> GetAllFiles(string dir)
|
||||
{
|
||||
DirectoryInfo directoryInfo = new(dir);
|
||||
return GetAllFiles(directoryInfo);
|
||||
}
|
||||
public static string OpenSlectDirDialog(string dirpath = "")
|
||||
{
|
||||
FolderBrowserDialog fbd = new FolderBrowserDialog();
|
||||
fbd.InitialDirectory = dirpath;
|
||||
if (fbd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
string targetDirPath = fbd.SelectedPath;
|
||||
if (Directory.Exists(targetDirPath))
|
||||
{
|
||||
return targetDirPath;
|
||||
}
|
||||
else
|
||||
return string.Empty;
|
||||
//ImportDirImages(targetDirPath);
|
||||
}
|
||||
else
|
||||
return string.Empty;
|
||||
}
|
||||
public static string OpenSlectfileDialog(string dirpath = "")
|
||||
{
|
||||
|
||||
|
||||
|
||||
// 创建并配置 OpenFileDialog 实例
|
||||
OpenFileDialog openFileDialog = new OpenFileDialog();
|
||||
openFileDialog.Title = "选择文件"; // 对话框标题
|
||||
openFileDialog.Filter = "所有文件 (*.pt)|*.*"; // 允许选择任何类型的文件
|
||||
openFileDialog.InitialDirectory = @"C:\"; // 初始显示目录,可以根据需要修改
|
||||
|
||||
// 显示对话框
|
||||
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
// 获取选中的文件路径
|
||||
string selectedFilePath = openFileDialog.FileName;
|
||||
Console.WriteLine("您选择的文件路径是: " + selectedFilePath);
|
||||
return selectedFilePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("没有选择任何文件。");
|
||||
return string.Empty;
|
||||
MessageBox.Show("没有选择任何文件。");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class FileInformation
|
||||
{
|
||||
public string FileName { get; set; }
|
||||
public string FilePath { get; set; }
|
||||
}
|
||||
}
|
107
DH.Commons/Helper/ImageSaveHelper.cs
Normal file
107
DH.Commons/Helper/ImageSaveHelper.cs
Normal file
@ -0,0 +1,107 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using DH.Commons.Helper;
|
||||
|
||||
namespace DH.Commons.Enums
|
||||
{
|
||||
public class ImageSaveHelper
|
||||
{
|
||||
public event Action<DateTime, string> OnImageSaveExceptionRaised;
|
||||
|
||||
//private string baseDirectory = "";
|
||||
//public string BaseDirectory
|
||||
//{
|
||||
// get => baseDirectory;
|
||||
// set
|
||||
// {
|
||||
// baseDirectory = value;
|
||||
// if (string.IsNullOrWhiteSpace(baseDirectory) || !Path.IsPathRooted(baseDirectory))
|
||||
// {
|
||||
// baseDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Images");
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
public bool EnableImageSave { get; set; } = true;
|
||||
|
||||
public ImageSaveHelper() { }
|
||||
public ImageSaveHelper(bool enableImageSave = true)
|
||||
{
|
||||
EnableImageSave = enableImageSave;
|
||||
}
|
||||
|
||||
|
||||
object lockObj = new object();
|
||||
////耗时操作从 _taskFactory分配线程
|
||||
//public TaskFactory _taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning);
|
||||
readonly ConcurrentQueue<ImageSaveSet> _imageQueue = new ConcurrentQueue<ImageSaveSet>();
|
||||
Task _saveTask = null;
|
||||
readonly object _saveLock = new object();
|
||||
|
||||
public async void ImageSaveAsync(ImageSaveSet set)
|
||||
{
|
||||
if (!EnableImageSave)
|
||||
return;
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
_imageQueue.Enqueue(set);
|
||||
|
||||
lock (_saveLock)
|
||||
{
|
||||
if (_saveTask == null)
|
||||
{
|
||||
_saveTask = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
while (_imageQueue.Count > 0)
|
||||
{
|
||||
if (_imageQueue.TryDequeue(out ImageSaveSet saveSet))
|
||||
{
|
||||
if (!Directory.Exists(Path.GetDirectoryName(saveSet.FullName)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(saveSet.FullName));
|
||||
}
|
||||
if (saveSet.SaveImage != null)
|
||||
{
|
||||
saveSet.SaveImage.Save(saveSet.FullName, saveSet.ImageFormat);
|
||||
saveSet.SaveImage.Dispose();
|
||||
}
|
||||
saveSet = null;
|
||||
}
|
||||
}
|
||||
|
||||
await Task.Delay(2000);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnImageSaveExceptionRaised?.Invoke(DateTime.Now, $"图片保存异常:{ex.GetExceptionMessage()}");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class ImageSaveSet
|
||||
{
|
||||
public string FullName { get; set; }//带后缀 全路径
|
||||
|
||||
public Bitmap SaveImage { get; set; }
|
||||
|
||||
public ImageFormat ImageFormat { get; set; } = ImageFormat.Jpeg;
|
||||
}
|
||||
}
|
138
DH.Commons/Helper/LoggerHelper.cs
Normal file
138
DH.Commons/Helper/LoggerHelper.cs
Normal file
@ -0,0 +1,138 @@
|
||||
using DH.Commons.Helper;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using static DH.Commons.Enums.EnumHelper;
|
||||
|
||||
namespace DH.Commons.Enums
|
||||
{
|
||||
public interface ILogOutput
|
||||
{
|
||||
event Action<LogMsg> OnLogMsgOutput;
|
||||
void LogDisplay(LogMsg msg);
|
||||
}
|
||||
public interface ILogger
|
||||
{
|
||||
event Action<LogMsg> OnLog;
|
||||
LoggerHelper LoggerHelper { get; set; }
|
||||
//void LogAsync(DateTime dt, LogLevel loglevel, string msg);
|
||||
void LogAsync(LogMsg msg);
|
||||
}
|
||||
public class LoggerHelper
|
||||
{
|
||||
public event Action<DateTime, string> OnLogExceptionRaised;
|
||||
|
||||
public string LogPath { get; set; }
|
||||
public string LogPrefix { get; set; }
|
||||
|
||||
LogLevel LogLevel = LogLevel.Information;
|
||||
|
||||
public LoggerHelper() { }
|
||||
public LoggerHelper(string logPath, string logPrefix, LogLevel logLevel = LogLevel.Information)
|
||||
{
|
||||
LogPath = logPath;
|
||||
LogPrefix = logPrefix;
|
||||
|
||||
LogLevel = logLevel;
|
||||
}
|
||||
|
||||
public void SetLogLevel(LogLevel logLevel)
|
||||
{
|
||||
if (LogLevel != logLevel)
|
||||
LogLevel = logLevel;
|
||||
}
|
||||
////耗时操作从 _taskFactory分配线程
|
||||
//public TaskFactory _taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning);
|
||||
readonly ConcurrentQueue<LogMsg> _logQueue = new ConcurrentQueue<LogMsg>();
|
||||
Task _logTask = null;
|
||||
readonly object _logLock = new object();
|
||||
|
||||
public async void LogAsync(LogMsg msg)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
_logQueue.Enqueue(msg);
|
||||
|
||||
lock (_logLock)
|
||||
{
|
||||
if (_logTask == null)
|
||||
{
|
||||
_logTask = Task.Run(async () =>
|
||||
{
|
||||
string filePath = Path.Combine(LogPath, $"{(string.IsNullOrWhiteSpace(LogPrefix) ? "Log_" : ("Log_" + LogPrefix + "_"))}{DateTime.Now.ToString("yyyyMMdd")}.txt");
|
||||
try
|
||||
{
|
||||
if (!StaticHelper.CheckFilesCanUse(filePath))
|
||||
{
|
||||
OnLogExceptionRaised?.Invoke(DateTime.Now, $"日志文件{filePath}被占用,无法写入");
|
||||
return;
|
||||
}
|
||||
using (StreamWriter writer = new StreamWriter(filePath, true, System.Text.Encoding.UTF8))
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (!Directory.Exists(LogPath))
|
||||
{
|
||||
Directory.CreateDirectory(LogPath);
|
||||
}
|
||||
|
||||
while (_logQueue.Count > 0)
|
||||
{
|
||||
if (_logQueue.TryDequeue(out LogMsg log))
|
||||
{
|
||||
if (log.LogLevel >= LogLevel)
|
||||
{
|
||||
writer.WriteLine($"{log.LogTime.ToString("yyyy-MM-dd HH:mm:ss.fff")}[{log.ThreadId}]\t{log.LogLevel.GetEnumDescription()}\t{log.Msg}");
|
||||
}
|
||||
}
|
||||
}
|
||||
writer.Flush();
|
||||
|
||||
await Task.Delay(2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//OnLogExceptionRaised?.Invoke(DateTime.Now, $"日志文件{filePath}写入异常:/*{ex.GetExceptionMessage()*/}");
|
||||
OnLogExceptionRaised?.Invoke(DateTime.Now, $"日志文件{filePath}写入异常");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void LogAsync(DateTime dt, LogLevel logLevel, string msg)
|
||||
{
|
||||
LogAsync(new LogMsg(dt, logLevel, msg));
|
||||
}
|
||||
}
|
||||
|
||||
public class LogMsg
|
||||
{
|
||||
public DateTime LogTime { get; set; }
|
||||
public LogLevel LogLevel { get; set; }
|
||||
//public string Prefix { get; set; }
|
||||
public string Msg { get; set; }
|
||||
|
||||
public string MsgSource { get; set; }
|
||||
|
||||
public int ThreadId { get; set; }
|
||||
|
||||
public LogMsg() { }
|
||||
public LogMsg(DateTime dt, LogLevel logLevel, string msg)
|
||||
{
|
||||
LogTime = dt;
|
||||
LogLevel = logLevel;
|
||||
Msg = msg;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{LogTime.ToString("HH:mm:ss.fff")}\t{MsgSource}\t{Msg}";
|
||||
}
|
||||
}
|
||||
}
|
169
DH.Commons/Helper/SchemeHelper.cs
Normal file
169
DH.Commons/Helper/SchemeHelper.cs
Normal file
@ -0,0 +1,169 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace DH.Commons.Helper
|
||||
{
|
||||
public static class SchemeHelper
|
||||
{
|
||||
private const string DefaultSchemeName = "默认方案";
|
||||
private static readonly string ConfigFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "schemes.json");
|
||||
|
||||
/// <summary>
|
||||
/// 方案配置数据结构
|
||||
/// </summary>
|
||||
private class SchemeConfig
|
||||
{
|
||||
public List<string> Schemes { get; set; } = new List<string>();
|
||||
public string CurrentScheme { get; set; } = DefaultSchemeName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化配置(首次运行时调用)
|
||||
/// </summary>
|
||||
public static void Initialize()
|
||||
{
|
||||
if (!File.Exists(ConfigFilePath))
|
||||
{
|
||||
var defaultConfig = new SchemeConfig
|
||||
{
|
||||
Schemes = new List<string> { DefaultSchemeName },
|
||||
CurrentScheme = DefaultSchemeName
|
||||
};
|
||||
SaveConfig(defaultConfig);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有方案
|
||||
/// </summary>
|
||||
public static List<string> GetAllSchemes()
|
||||
{
|
||||
var config = LoadConfig();
|
||||
return config.Schemes ?? new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加新方案
|
||||
/// </summary>
|
||||
public static void AddScheme(string schemeName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(schemeName))
|
||||
throw new ArgumentException("方案名称无效");
|
||||
|
||||
var config = LoadConfig();
|
||||
|
||||
if (config.Schemes.Contains(schemeName))
|
||||
throw new InvalidOperationException($"方案 {schemeName} 已存在");
|
||||
|
||||
config.Schemes.Add(schemeName);
|
||||
SaveConfig(config);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置当前方案
|
||||
/// </summary>
|
||||
public static void SetCurrentScheme(string schemeName)
|
||||
{
|
||||
var config = LoadConfig();
|
||||
|
||||
if (!config.Schemes.Contains(schemeName))
|
||||
throw new KeyNotFoundException($"方案 {schemeName} 不存在");
|
||||
|
||||
config.CurrentScheme = schemeName;
|
||||
SaveConfig(config);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前方案
|
||||
/// </summary>
|
||||
public static string GetCurrentScheme()
|
||||
{
|
||||
var config = LoadConfig();
|
||||
return !string.IsNullOrEmpty(config.CurrentScheme)
|
||||
? config.CurrentScheme
|
||||
: DefaultSchemeName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除指定方案
|
||||
/// </summary>
|
||||
public static void DeleteScheme(string schemeName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(schemeName))
|
||||
throw new ArgumentException("方案名称无效");
|
||||
|
||||
var config = LoadConfig();
|
||||
|
||||
if (!config.Schemes.Contains(schemeName))
|
||||
throw new KeyNotFoundException($"方案 {schemeName} 不存在");
|
||||
|
||||
// 如果是当前方案,需要先切换
|
||||
if (config.CurrentScheme == schemeName)
|
||||
{
|
||||
var otherScheme = config.Schemes.FirstOrDefault(s => s != schemeName);
|
||||
if (otherScheme != null)
|
||||
{
|
||||
config.CurrentScheme = otherScheme;
|
||||
}
|
||||
else
|
||||
{
|
||||
config.CurrentScheme = DefaultSchemeName;
|
||||
if (!config.Schemes.Contains(DefaultSchemeName))
|
||||
{
|
||||
config.Schemes.Add(DefaultSchemeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config.Schemes.Remove(schemeName);
|
||||
SaveConfig(config);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载配置文件
|
||||
/// </summary>
|
||||
private static SchemeConfig LoadConfig()
|
||||
{
|
||||
if (!File.Exists(ConfigFilePath))
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string json = File.ReadAllText(ConfigFilePath);
|
||||
return JsonConvert.DeserializeObject<SchemeConfig>(json) ?? new SchemeConfig();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 如果读取失败,返回默认配置
|
||||
return new SchemeConfig
|
||||
{
|
||||
Schemes = new List<string> { DefaultSchemeName },
|
||||
CurrentScheme = DefaultSchemeName
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存配置文件
|
||||
/// </summary>
|
||||
private static void SaveConfig(SchemeConfig config)
|
||||
{
|
||||
try
|
||||
{
|
||||
string json = JsonConvert.SerializeObject(config, Formatting.Indented);
|
||||
File.WriteAllText(ConfigFilePath, json);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 处理保存失败的情况
|
||||
throw new InvalidOperationException("保存方案配置失败", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
680
DH.Commons/Helper/StaticHelper.cs
Normal file
680
DH.Commons/Helper/StaticHelper.cs
Normal file
@ -0,0 +1,680 @@
|
||||
using Microsoft.CSharp.RuntimeBinder;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Dynamic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
|
||||
namespace DH.Commons.Helper
|
||||
{
|
||||
public static class StaticHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 数值转换为byte数组 高位在前,低位在后
|
||||
/// </summary>
|
||||
/// <param name="number"></param>
|
||||
/// <param name="size"></param>
|
||||
/// <returns></returns>
|
||||
public static byte[] IntToBytes(this int number, int size = 2)
|
||||
{
|
||||
byte[] result = new byte[size];
|
||||
|
||||
int temp = size;
|
||||
while (temp > 0)
|
||||
{
|
||||
result[size - temp] = (byte)(number >> ((temp - 1) * 8) & 0xff);
|
||||
|
||||
temp--;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
public static T DeepSerializeClone<T>(this T t)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(t));
|
||||
}
|
||||
/// <summary>
|
||||
/// 字节数组转换为整数
|
||||
/// </summary>
|
||||
/// <param name="data">字节数组</param>
|
||||
/// <param name="HtL">true:数组序号低的在高位 false:数组序号低的在低位</param>
|
||||
/// <returns></returns>
|
||||
public static int BytesToInt(this byte[] data, bool HtL = true)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
int index = i;
|
||||
|
||||
if (HtL)
|
||||
{
|
||||
index = data.Length - 1 - i;
|
||||
}
|
||||
|
||||
res += data[index] << (8 * i);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取一个类指定的属性值
|
||||
/// </summary>
|
||||
/// <param name="info">object对象</param>
|
||||
/// <param name="field">属性名称</param>
|
||||
/// <returns></returns>
|
||||
public static object GetPropertyValue(object info, string field)
|
||||
{
|
||||
if (info == null) return null;
|
||||
Type t = info.GetType();
|
||||
IEnumerable<System.Reflection.PropertyInfo> property = from pi in t.GetProperties() where pi.Name.ToLower() == field.ToLower() select pi;
|
||||
return property.First().GetValue(info, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将32位整形拆分为无符号16位整形
|
||||
/// </summary>
|
||||
/// <param name="num">需要拆分的32位整形</param>
|
||||
/// <param name="bitNum">拆分为16位整形的位数 1或者2</param>
|
||||
/// <param name="HtL">true:高位在前,低位在后;false:高位在后,低位在前</param>
|
||||
/// <returns></returns>
|
||||
public static List<ushort> ParseIntToUnsignShortList(this int num, int bitNum = 2, bool HtL = false)
|
||||
{
|
||||
if (bitNum == 2)
|
||||
{
|
||||
ushort high = (ushort)(num >> 16);
|
||||
ushort low = (ushort)num;
|
||||
|
||||
if (HtL)
|
||||
{
|
||||
return new List<ushort>() { high, low };
|
||||
}
|
||||
else
|
||||
{
|
||||
return new List<ushort>() { low, high };
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (num < 0)
|
||||
{
|
||||
num = ushort.MaxValue + 1 + num;
|
||||
}
|
||||
|
||||
return new List<ushort>() { (ushort)num };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将32位整形数组拆分为无符号16位整形数组
|
||||
/// </summary>
|
||||
/// <param name="list">需要拆分的32位整形</param>
|
||||
/// <param name="bitNum">拆分为16位整形的位数 1或者2</param>
|
||||
/// <param name="HtL">true:高位在前,低位在后;false:高位在后,低位在前</param>
|
||||
/// <returns></returns>
|
||||
public static List<ushort> ParseIntToUnsignShortList(this List<int> list, int bitNum = 2, bool HtL = false)
|
||||
{
|
||||
return list.SelectMany(u => u.ParseIntToUnsignShortList(bitNum, HtL)).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将ushort的集合转换为16位带符号整形
|
||||
/// </summary>
|
||||
/// <param name="numList"></param>
|
||||
/// <param name="bitNum">合并的位数 1或者2</param>
|
||||
/// <param name="HtL">true:高位在前,低位在后;false:高位在后,低位在前</param>
|
||||
/// <returns></returns>
|
||||
public static List<int> ParseUnsignShortListToInt(this List<int> numList, int bitNum = 2, bool HtL = false)
|
||||
{
|
||||
if (bitNum == 1)
|
||||
{
|
||||
return numList.ConvertAll(n =>
|
||||
{
|
||||
int num = n;
|
||||
if (num > short.MaxValue)
|
||||
{
|
||||
num = num - ushort.MaxValue - 1;
|
||||
}
|
||||
|
||||
return num;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
List<int> list = new List<int>();
|
||||
for (int i = 0; i < numList.Count; i += 2)
|
||||
{
|
||||
int high = HtL ? numList[i] : numList[i + 1];
|
||||
int low = HtL ? numList[i + 1] : numList[i];
|
||||
list.Add((high << 16) | low);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
//public static T DeepSerializeClone<T>(this T t)
|
||||
//{
|
||||
// return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(t));
|
||||
//}
|
||||
|
||||
public static void DataFrom<T1, T2>(this T1 destT, T2 sourceT, List<string> exceptionProps = null) where T1 : class where T2 : class
|
||||
{
|
||||
if (sourceT == null)
|
||||
{
|
||||
destT = null;
|
||||
return;
|
||||
}
|
||||
|
||||
PropertyInfo[] propDest = destT.GetType().GetProperties();//.Where(p => !(p.GetMethod.IsVirtual && !p.GetMethod.IsFinal)).ToArray();
|
||||
PropertyInfo[] propSource = sourceT.GetType().GetProperties();
|
||||
|
||||
Array.ForEach(propDest, prop =>
|
||||
{
|
||||
if (exceptionProps == null || !exceptionProps.Contains(prop.Name))
|
||||
{
|
||||
if (prop.CanWrite)
|
||||
{
|
||||
PropertyInfo propS = propSource.FirstOrDefault(p => p.Name == prop.Name);
|
||||
if (propS != null && propS.CanRead)
|
||||
{
|
||||
prop.SetValue(destT, propS.GetValue(sourceT));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//RtlMoveMemory
|
||||
[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
|
||||
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
|
||||
[HandleProcessCorruptedStateExceptions]
|
||||
//public static Bitmap CopyBitmap(this Bitmap source)
|
||||
//{
|
||||
// Bitmap clone = new Bitmap(source.Width, source.Height, source.PixelFormat);
|
||||
// try
|
||||
// {
|
||||
// int PixelSize = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8;
|
||||
// if (PixelSize == 1)
|
||||
// {
|
||||
// ColorPalette cp = clone.Palette;
|
||||
// for (int i = 0; i < 256; i++)
|
||||
// {
|
||||
// cp.Entries[i] = Color.FromArgb(255, i, i, i);
|
||||
// }
|
||||
// clone.Palette = cp;
|
||||
// }
|
||||
|
||||
// Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
|
||||
// BitmapData sourceData = source.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat);
|
||||
// BitmapData cloneData = clone.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat);
|
||||
// if (source.Width % 4 == 0)
|
||||
// {
|
||||
// unsafe
|
||||
// {
|
||||
// CopyMemory(cloneData.Scan0, sourceData.Scan0, (uint)(sourceData.Stride * sourceData.Height));
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Parallel.For(0, source.Height, h =>
|
||||
// {
|
||||
// unsafe
|
||||
// {
|
||||
// CopyMemory(cloneData.Scan0 + h * sourceData.Stride, sourceData.Scan0 + h * sourceData.Stride, (uint)sourceData.Width);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
// clone.UnlockBits(cloneData);
|
||||
// source.UnlockBits(sourceData);
|
||||
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// return clone;
|
||||
// }
|
||||
|
||||
// return clone;
|
||||
//}
|
||||
public static Bitmap CopyBitmap(this Bitmap source)
|
||||
{
|
||||
Bitmap clone = new Bitmap(source.Width, source.Height, source.PixelFormat);
|
||||
|
||||
try
|
||||
{
|
||||
int pixelSize = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8;
|
||||
if (pixelSize == 1)
|
||||
{
|
||||
ColorPalette cp = clone.Palette;
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
cp.Entries[i] = Color.FromArgb(255, i, i, i);
|
||||
}
|
||||
clone.Palette = cp;
|
||||
}
|
||||
|
||||
Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
|
||||
BitmapData sourceData = source.LockBits(rect, ImageLockMode.ReadOnly, source.PixelFormat);
|
||||
BitmapData cloneData = clone.LockBits(rect, ImageLockMode.WriteOnly, source.PixelFormat);
|
||||
|
||||
int stride = sourceData.Stride;
|
||||
int height = sourceData.Height;
|
||||
|
||||
if (stride % 4 == 0)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
CopyMemory(cloneData.Scan0, sourceData.Scan0, (uint)(stride * height));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Parallel.For(0, height, h =>
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
CopyMemory(cloneData.Scan0 + h * stride, sourceData.Scan0 + h * stride, (uint)stride);
|
||||
}
|
||||
});
|
||||
}
|
||||
source.UnlockBits(sourceData); clone.UnlockBits(cloneData);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{ // Handle or log exception if needed
|
||||
} return clone; }
|
||||
|
||||
|
||||
public static Bitmap BitmapDeepClone(Bitmap source)
|
||||
{
|
||||
Bitmap clone = new Bitmap(source.Width, source.Height, source.PixelFormat);
|
||||
|
||||
try
|
||||
{
|
||||
int PixelSize = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8;
|
||||
if (PixelSize == 1)
|
||||
{
|
||||
ColorPalette cp = clone.Palette;
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
cp.Entries[i] = Color.FromArgb(255, i, i, i);
|
||||
}
|
||||
clone.Palette = cp;
|
||||
}
|
||||
Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
|
||||
BitmapData source_bitmap = source.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat);
|
||||
BitmapData destination_bitmap = clone.LockBits(rect, ImageLockMode.ReadWrite, clone.PixelFormat);
|
||||
|
||||
int depth_width = source_bitmap.Width * PixelSize;
|
||||
|
||||
unsafe
|
||||
{
|
||||
byte* source_ptr = (byte*)source_bitmap.Scan0;
|
||||
byte* destination_ptr = (byte*)destination_bitmap.Scan0;
|
||||
|
||||
int offset = source_bitmap.Stride - depth_width;
|
||||
|
||||
for (int i = 0; i < source_bitmap.Height; i++)
|
||||
{
|
||||
for (int j = 0; j < depth_width; j++, source_ptr++, destination_ptr++)
|
||||
{
|
||||
*destination_ptr = *source_ptr;
|
||||
}
|
||||
|
||||
source_ptr += offset;
|
||||
destination_ptr += offset;
|
||||
}
|
||||
}
|
||||
|
||||
source.UnlockBits(source_bitmap);
|
||||
clone.UnlockBits(destination_bitmap);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static Bitmap HConnectBitmap(this Bitmap map1, Bitmap map2)
|
||||
{
|
||||
Bitmap connectImage = null;
|
||||
if (map1 == null || map2 == null)
|
||||
return null;
|
||||
//横向拼接
|
||||
int width = map1.Width + map2.Width;
|
||||
//高度不变
|
||||
int height = Math.Max(map1.Height, map2.Height);
|
||||
connectImage = new Bitmap(width, height);
|
||||
using (Graphics graph = Graphics.FromImage(connectImage))
|
||||
{
|
||||
graph.DrawImage(connectImage, width, height);
|
||||
graph.Clear(System.Drawing.Color.White);
|
||||
graph.DrawImage(map1, 0, 0);
|
||||
graph.DrawImage(map2, map1.Width, 0);
|
||||
}
|
||||
return connectImage;
|
||||
}
|
||||
|
||||
public static IntPtr FloatToIntptr(float[] bytes)
|
||||
{
|
||||
GCHandle hObject = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
||||
return hObject.AddrOfPinnedObject();
|
||||
}
|
||||
|
||||
// 将Btimap类转换为byte[]类函数
|
||||
public static byte[] GetBGRValues(Bitmap bmp, out int stride)
|
||||
{
|
||||
var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
|
||||
var bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat);
|
||||
stride = bmpData.Stride;
|
||||
var rowBytes = bmpData.Width * Image.GetPixelFormatSize(bmp.PixelFormat) / 8;
|
||||
var imgBytes = bmp.Height * rowBytes;
|
||||
byte[] rgbValues = new byte[imgBytes];
|
||||
IntPtr ptr = bmpData.Scan0;
|
||||
for (var i = 0; i < bmp.Height; i++)
|
||||
{
|
||||
Marshal.Copy(ptr, rgbValues, i * rowBytes, rowBytes);
|
||||
ptr += bmpData.Stride;
|
||||
}
|
||||
bmp.UnlockBits(bmpData);
|
||||
return rgbValues;
|
||||
}
|
||||
/// <summary>
|
||||
/// 缺陷灰度图转彩色图像函数
|
||||
/// </summary>
|
||||
/// <param name="src">灰度图</param>
|
||||
/// <returns>返回构造的伪彩色图像</returns>
|
||||
public static Bitmap GrayMapToColorMap(this Bitmap src, Dictionary<int, Color> indexColorDict = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
//Stopwatch sw = new Stopwatch();
|
||||
//sw.Start();
|
||||
|
||||
Bitmap dest = new Bitmap(src.Width, src.Height, PixelFormat.Format32bppArgb);
|
||||
|
||||
int destHeight = dest.Height;
|
||||
int destWidth = dest.Width;
|
||||
|
||||
Rectangle rect = new Rectangle(0, 0, destWidth, destHeight);
|
||||
BitmapData bmpDataDest = dest.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||
BitmapData bmpDataSrc = src.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
|
||||
int strideDest = bmpDataDest.Stride;
|
||||
|
||||
int strideSrc = bmpDataSrc.Stride;
|
||||
unsafe
|
||||
{
|
||||
byte* pDest = (byte*)bmpDataDest.Scan0.ToPointer();
|
||||
byte* pSrc = (byte*)bmpDataSrc.Scan0.ToPointer();
|
||||
|
||||
Parallel.For(0, destHeight, y =>
|
||||
{
|
||||
Parallel.For(0, destWidth, x =>
|
||||
{
|
||||
int pixel = pSrc[y * strideSrc + x];
|
||||
int startIndex = y * strideDest + x * 4;
|
||||
if (pixel >= 0 && pixel <= 63)
|
||||
{
|
||||
Color color = Color.Red;
|
||||
if (indexColorDict != null && indexColorDict.ContainsKey(pixel))
|
||||
{
|
||||
color = indexColorDict[pixel];
|
||||
}
|
||||
|
||||
byte R = color.R;
|
||||
byte G = color.G;
|
||||
byte B = color.B;
|
||||
|
||||
pDest[startIndex] = B;
|
||||
pDest[startIndex + 1] = G;
|
||||
pDest[startIndex + 2] = R;
|
||||
pDest[startIndex + 3] = 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
pDest[startIndex] = 255;
|
||||
pDest[startIndex + 1] = 255;
|
||||
pDest[startIndex + 2] = 255;
|
||||
pDest[startIndex + 3] = 0;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
dest.UnlockBits(bmpDataDest);
|
||||
src.UnlockBits(bmpDataSrc);
|
||||
|
||||
//sw.Stop();
|
||||
//Console.WriteLine($"转换耗时:{sw.ElapsedMilliseconds}");
|
||||
|
||||
return dest;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sort<T>(this ObservableCollection<T> collection) where T : IComparable<T>
|
||||
{
|
||||
List<T> sortedList = collection.OrderByDescending(x => x).ToList();//这里用降序
|
||||
for (int i = 0; i < sortedList.Count(); i++)
|
||||
{
|
||||
collection.Move(collection.IndexOf(sortedList[i]), i);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得字符串中开始和结束字符串中间的值
|
||||
/// </summary>
|
||||
/// <param name="sourse"></param>
|
||||
/// <param name="startstr"></param>
|
||||
/// <param name="endstr"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetMidString(string sourse, string startstr, string endstr)
|
||||
{
|
||||
string result = string.Empty;
|
||||
int startindex, endindex;
|
||||
try
|
||||
{
|
||||
startindex = sourse.IndexOf(startstr);
|
||||
if (startindex == -1)
|
||||
return result;
|
||||
string tmpstr = sourse.Substring(startindex + startstr.Length);
|
||||
endindex = tmpstr.IndexOf(endstr);
|
||||
if (endindex == -1)
|
||||
return result;
|
||||
result = tmpstr.Remove(endindex);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得字符串中开始和结束字符串中间的值
|
||||
/// </summary>
|
||||
/// <param name="t">字符串</param>
|
||||
/// <param name="k">开始</param>
|
||||
/// <param name="j">结束</param>
|
||||
/// <returns></returns>
|
||||
private static string GetMidString2(string sourse, string startstr, string endstr) //截取指定文本,和易语言的取文本中间差不多
|
||||
{
|
||||
try //异常捕捉
|
||||
{
|
||||
var kn = sourse.IndexOf(startstr, StringComparison.Ordinal) + startstr.Length;
|
||||
var jn = sourse.IndexOf(endstr, kn, StringComparison.Ordinal);
|
||||
return sourse.Substring(kn, jn - kn);
|
||||
}
|
||||
catch //如果发现未知的错误,比如上面的代码出错了,就执行下面这句代码
|
||||
{
|
||||
return ""; //返回空
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 布尔类型转换为整型
|
||||
public static int ToInt(this object obj)
|
||||
{
|
||||
if (Convert.ToBoolean(obj) == true)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 整型转换为布尔类型
|
||||
public static bool ToBool(this object obj)
|
||||
{
|
||||
if (Convert.ToInt32(obj) == 1)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public static object GetProperty(this object o, string member)
|
||||
{
|
||||
if (o == null) throw new ArgumentNullException("o");
|
||||
if (member == null) throw new ArgumentNullException("member");
|
||||
Type scope = o.GetType();
|
||||
IDynamicMetaObjectProvider provider = o as IDynamicMetaObjectProvider;
|
||||
if (provider != null)
|
||||
{
|
||||
ParameterExpression param = Expression.Parameter(typeof(object));
|
||||
DynamicMetaObject mobj = provider.GetMetaObject(param);
|
||||
GetMemberBinder binder = (GetMemberBinder)Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, member, scope, new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(0, null) });
|
||||
DynamicMetaObject ret = mobj.BindGetMember(binder);
|
||||
BlockExpression final = Expression.Block(
|
||||
Expression.Label(CallSiteBinder.UpdateLabel),
|
||||
ret.Expression
|
||||
);
|
||||
LambdaExpression lambda = Expression.Lambda(final, param);
|
||||
Delegate del = lambda.Compile();
|
||||
return del.DynamicInvoke(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
return o.GetType().GetProperty(member, BindingFlags.Public | BindingFlags.Instance).GetValue(o, null);
|
||||
}
|
||||
}
|
||||
|
||||
#region 检测文件状态及操作方式选择
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern IntPtr _lopen(string lpPathName, int iReadWrite);
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern bool CloseHandle(IntPtr hObject);
|
||||
private const int OF_READWRITE = 2;
|
||||
private const int OF_SHARE_DENY_NONE = 0x40;
|
||||
private static readonly IntPtr HFILE_ERROR = new IntPtr(-1);
|
||||
/// <summary>
|
||||
/// 检测文件是否只读或被使用
|
||||
/// </summary>
|
||||
/// <param name="FileNames">要检测的文件</param>
|
||||
/// <returns>true可用,false在用或只读</returns>
|
||||
public static bool CheckFilesCanUse(string fileName)
|
||||
{
|
||||
if (!File.Exists(fileName))
|
||||
return true;//文件不存在
|
||||
if ((File.GetAttributes(fileName) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
|
||||
return false; //文件只读
|
||||
IntPtr vHandle = _lopen(fileName, OF_READWRITE | OF_SHARE_DENY_NONE);
|
||||
if (vHandle == HFILE_ERROR)
|
||||
{
|
||||
CloseHandle(vHandle);
|
||||
return false; //文件被占用
|
||||
}
|
||||
|
||||
CloseHandle(vHandle); //文件没被占用
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定文件夹下所有的文件名称
|
||||
/// </summary>
|
||||
/// <param name="folderName">指定文件夹名称,绝对路径</param>
|
||||
/// <param name="fileFilter">文件类型过滤,根据文件后缀名,如:*,*.txt,*.xls</param>
|
||||
/// <param name="isContainSubFolder">是否包含子文件夹</param>
|
||||
/// <returns>ArrayList数组,为所有需要的文件路径名称</returns>
|
||||
public static List<FileInfo> GetAllFilesByFolder(string folderName, string fileFilter, bool isContainSubFolder = false)
|
||||
{
|
||||
List<FileInfo> resList = new List<FileInfo>();
|
||||
try
|
||||
{
|
||||
DirectoryInfo currDir = new DirectoryInfo(folderName);//当前目录
|
||||
FileInfo[] currFiles = currDir.GetFiles(fileFilter);//当前目录文件
|
||||
foreach (FileInfo file in currFiles)
|
||||
{
|
||||
if (fileFilter.ToLower().IndexOf(file.Extension.ToLower()) >= 0)
|
||||
{
|
||||
resList.Add(file);
|
||||
}
|
||||
}
|
||||
if (isContainSubFolder)
|
||||
{
|
||||
string[] subFolders = Directory.GetDirectories(folderName);
|
||||
foreach (string subFolder in subFolders)
|
||||
{
|
||||
resList.AddRange(GetAllFilesByFolder(subFolder, fileFilter));//递归
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
return resList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定文件夹下所有的文件名称,不过滤文件类型
|
||||
/// </summary>
|
||||
/// <param name="folderName">指定文件夹名称,绝对路径</param>
|
||||
/// <param name="isContainSubFolder">是否包含子文件夹</param>
|
||||
/// <returns>ArrayList数组,为所有需要的文件路径名称</returns>
|
||||
public static List<FileInfo> GetAllFilesByFolder(string folderName, bool isContainSubFolder)
|
||||
{
|
||||
return GetAllFilesByFolder(folderName, "*", isContainSubFolder);
|
||||
}
|
||||
}
|
||||
|
||||
public class Compare<T, C> : IEqualityComparer<T>
|
||||
{
|
||||
private Func<T, C> _getField;
|
||||
public Compare(Func<T, C> getfield)
|
||||
{
|
||||
_getField = getfield;
|
||||
}
|
||||
public bool Equals(T x, T y)
|
||||
{
|
||||
return EqualityComparer<C>.Default.Equals(_getField(x), _getField(y));
|
||||
}
|
||||
public int GetHashCode(T obj)
|
||||
{
|
||||
return EqualityComparer<C>.Default.GetHashCode(_getField(obj));
|
||||
}
|
||||
}
|
||||
|
||||
public static class ObjectExtensions
|
||||
{
|
||||
public static IEnumerable<T> DistinctBy<T, C>(this IEnumerable<T> source, Func<T, C> getfield)
|
||||
{
|
||||
return source.Distinct(new Compare<T, C>(getfield));
|
||||
}
|
||||
|
||||
public static IQueryable<T> DistinctBy<T, C>(this IQueryable<T> source, Func<T, C> getfield)
|
||||
{
|
||||
return source.Distinct(new Compare<T, C>(getfield));
|
||||
}
|
||||
}
|
||||
}
|
120
DH.Commons/Helper/SystemConfigHelper.cs
Normal file
120
DH.Commons/Helper/SystemConfigHelper.cs
Normal file
@ -0,0 +1,120 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DH.Commons.Helper
|
||||
{
|
||||
/// <summary>
|
||||
/// 配置文件操作工具类(自动定位主程序配置)
|
||||
/// </summary>
|
||||
public static class SystemConfigHelper
|
||||
{
|
||||
private static Configuration _mainConfig;
|
||||
private static readonly object _lock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// 获取主程序配置对象
|
||||
/// </summary>
|
||||
private static Configuration MainConfiguration
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_mainConfig == null)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_mainConfig == null)
|
||||
{
|
||||
// 获取主程序路径
|
||||
string exePath = Assembly.GetEntryAssembly().Location;
|
||||
var configFile = exePath + ".config";
|
||||
|
||||
// 加载主程序配置
|
||||
var fileMap = new ExeConfigurationFileMap
|
||||
{
|
||||
ExeConfigFilename = configFile
|
||||
};
|
||||
_mainConfig = ConfigurationManager.OpenMappedExeConfiguration(
|
||||
fileMap,
|
||||
ConfigurationUserLevel.None
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return _mainConfig;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查配置项是否存在
|
||||
/// </summary>
|
||||
public static bool KeyExists(string key)
|
||||
{
|
||||
return MainConfiguration.AppSettings.Settings[key] != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取配置项(带类型自动转换)
|
||||
/// </summary>
|
||||
public static T GetValue<T>(string key, T defaultValue = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var setting = MainConfiguration.AppSettings.Settings[key];
|
||||
if (setting == null) return defaultValue;
|
||||
|
||||
return (T)Convert.ChangeType(setting.Value, typeof(T));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入配置项(自动保存)
|
||||
/// </summary>
|
||||
public static void SetValue(string key, object value)
|
||||
{
|
||||
var settings = MainConfiguration.AppSettings.Settings;
|
||||
var stringValue = value?.ToString() ?? string.Empty;
|
||||
|
||||
if (settings[key] == null)
|
||||
{
|
||||
settings.Add(key, stringValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
settings[key].Value = stringValue;
|
||||
}
|
||||
|
||||
SaveChanges();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除指定配置项
|
||||
/// </summary>
|
||||
public static void RemoveKey(string key)
|
||||
{
|
||||
if (KeyExists(key))
|
||||
{
|
||||
MainConfiguration.AppSettings.Settings.Remove(key);
|
||||
SaveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存配置修改
|
||||
/// </summary>
|
||||
private static void SaveChanges()
|
||||
{
|
||||
MainConfiguration.Save(ConfigurationSaveMode.Modified);
|
||||
ConfigurationManager.RefreshSection("appSettings");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
109
DH.Commons/Interface/Spec.cs
Normal file
109
DH.Commons/Interface/Spec.cs
Normal file
@ -0,0 +1,109 @@
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing.Design;
|
||||
|
||||
namespace DH.Commons.Enums
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 标准配置
|
||||
/// </summary>
|
||||
public class Spec
|
||||
{
|
||||
[Category("通用配置")]
|
||||
[Description("标准代码")]
|
||||
public virtual string Code { get; set; }
|
||||
|
||||
[Category("通用配置")]
|
||||
[Description("启用状态,true:启用;false:禁用")]
|
||||
[DisplayName("启用状态")]
|
||||
public bool IsEnabled { get; set; }
|
||||
|
||||
[Category("标准配置")]
|
||||
[Description("标准值")]
|
||||
[DisplayName("标准值")]
|
||||
public double StandardValue { get; set; }
|
||||
|
||||
[Category("标准配置")]
|
||||
[Description("正公差")]
|
||||
[DisplayName("正公差")]
|
||||
public double Tolrenance_Positive { get; set; }
|
||||
|
||||
[Category("标准配置")]
|
||||
[Description("负公差")]
|
||||
[DisplayName("负公差")]
|
||||
public double Tolrenance_Negative { get; set; }
|
||||
|
||||
protected double? actualValue = null;
|
||||
[Browsable(false)]
|
||||
|
||||
public virtual double? ActualValue
|
||||
{
|
||||
get
|
||||
{
|
||||
return actualValue;
|
||||
}
|
||||
set
|
||||
{
|
||||
//if (actualValue != value && value != null)
|
||||
if (value != null)
|
||||
{
|
||||
if (value.Value >= (StandardValue - Tolrenance_Negative) && value.Value <= (StandardValue + Tolrenance_Positive))
|
||||
{
|
||||
MeasureResult = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
MeasureResult = false;
|
||||
}
|
||||
}
|
||||
|
||||
actualValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
[Browsable(false)]
|
||||
|
||||
public bool? MeasureResult { get; set; } = null;
|
||||
|
||||
|
||||
public Spec Copy()
|
||||
{
|
||||
Spec spec = new Spec();
|
||||
|
||||
spec.Code = this.Code;
|
||||
spec.IsEnabled = this.IsEnabled;
|
||||
spec.StandardValue = this.StandardValue;
|
||||
spec.Tolrenance_Positive = this.Tolrenance_Positive;
|
||||
spec.Tolrenance_Negative = this.Tolrenance_Negative;
|
||||
|
||||
return spec;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class IndexedSpec : Spec
|
||||
{
|
||||
[Category("数据源配置")]
|
||||
[Description("数据源输出索引")]
|
||||
[DisplayName("数据源输出索引")]
|
||||
public int OutputIndex { get; set; }
|
||||
|
||||
public new IndexedSpec Copy()
|
||||
{
|
||||
IndexedSpec spec = new IndexedSpec();
|
||||
|
||||
spec.Code = this.Code;
|
||||
spec.IsEnabled = this.IsEnabled;
|
||||
spec.StandardValue = this.StandardValue;
|
||||
spec.Tolrenance_Positive = this.Tolrenance_Positive;
|
||||
spec.Tolrenance_Negative = this.Tolrenance_Negative;
|
||||
|
||||
spec.OutputIndex = this.OutputIndex;
|
||||
|
||||
return spec;
|
||||
}
|
||||
}
|
||||
}
|
26
DH.Commons/Models/ProductSummary.cs
Normal file
26
DH.Commons/Models/ProductSummary.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DH.Commons.Models
|
||||
{
|
||||
public class CameraSummary
|
||||
{
|
||||
public string CameraName { get; set; } // 相机名称
|
||||
public int TiggerCount { get; set; } //触发数
|
||||
public int OKCount { get; set; } // OK 数
|
||||
public int NGCount { get; set; } // NG 数
|
||||
public int TotalCount => OKCount + NGCount; // 总检测数量
|
||||
public string YieldStr => $"{Yield:f2} %"; // 良率(字符串形式)
|
||||
public double Yield => OKCount + NGCount > 0 ? (double)OKCount / (OKCount + NGCount) * 100 : 0;
|
||||
}
|
||||
|
||||
public class ProductSummary
|
||||
{
|
||||
public int ProductAmount { get; set; }
|
||||
public string ResultDesc { get; set; }
|
||||
public string PercentStr { get; set; }
|
||||
}
|
||||
}
|
34
DH.Commons/Models/SystemModel.cs
Normal file
34
DH.Commons/Models/SystemModel.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using DH.Commons.Base;
|
||||
using DH.Commons.Enums;
|
||||
|
||||
namespace DH.Commons.Models
|
||||
{
|
||||
public static class SystemModel
|
||||
{
|
||||
/// <summary>
|
||||
/// 当前方案
|
||||
/// </summary>
|
||||
public static string CurrentScheme=string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 当前状态
|
||||
/// </summary>
|
||||
public static EnumStatus CurrentStatus =EnumStatus.待机中;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置集合
|
||||
/// </summary>
|
||||
public static class ConfigModel
|
||||
{
|
||||
public static List<CameraBase> CameraBaseList = new List<CameraBase>();
|
||||
public static List<PLCBase> PLCBaseList = new List<PLCBase>();
|
||||
public static List<DetectionConfig> DetectionList = new List<DetectionConfig>();
|
||||
public static List<GlobalConfig> GlobalList = new List<GlobalConfig>();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user