using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using JmSetupSheetReceiver.Models;
using Newtonsoft.Json;
namespace JmSetupSheetReceiver
{
///
/// 最近一次成功还原的程序单对象,便于调试器监视与控制台命令操作。
///
internal static class SetupSheetStore
{
private static readonly object Gate = new object();
private static SetupsheetData _latest;
private static string _latestJsonPath;
private static string _latestTxtPath;
private static DateTime _latestUtc;
public static SetupsheetData Latest
{
get { lock (Gate) { return _latest; } }
}
public static string LatestJsonPath
{
get { lock (Gate) { return _latestJsonPath; } }
}
public static string LatestTxtPath
{
get { lock (Gate) { return _latestTxtPath; } }
}
public static DateTime LatestUtc
{
get { lock (Gate) { return _latestUtc; } }
}
public static void SetLatest(SetupsheetData data, string jsonPath, string txtPath = null)
{
lock (Gate)
{
_latest = data;
_latestJsonPath = jsonPath;
_latestTxtPath = txtPath;
_latestUtc = DateTime.UtcNow;
}
}
}
///
/// 对已还原对象的查看 / 导出操作(控制台与学习演示用)。
///
internal static class SetupSheetOps
{
public static readonly JsonSerializerSettings JsonSettings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
Formatting = Formatting.Indented,
DateParseHandling = DateParseHandling.None
};
public static SetupsheetData Deserialize(string json)
{
return JsonConvert.DeserializeObject(json, JsonSettings);
}
public static string Serialize(SetupsheetData data)
{
return JsonConvert.SerializeObject(data, JsonSettings);
}
///
/// 生成带中文字段名的分层明文(预览图只写字节摘要,不输出 Base64)。
///
public static string ToPlainText(SetupsheetData data)
{
var sb = new StringBuilder();
if (data == null)
{
sb.AppendLine("(无对象)");
return sb.ToString();
}
sb.AppendLine("[程序单]");
Line(sb, 1, "串联坐标名称", "NcWpName", data.NcWpName);
Line(sb, 1, "精公火花位", "ThicknessF", data.ThicknessF);
Line(sb, 1, "中公火花位", "ThicknessM", data.ThicknessM);
Line(sb, 1, "粗公火花位", "ThicknessR", data.ThicknessR);
Line(sb, 1, "精公数量", "NumberF", data.NumberF);
Line(sb, 1, "中公数量", "NumberM", data.NumberM);
Line(sb, 1, "粗公数量", "NumberR", data.NumberR);
Line(sb, 1, "精公自动换刀NC", "AutoToolChangNcF", data.AutoToolChangNcF);
Line(sb, 1, "中公自动换刀NC", "AutoToolChangNcM", data.AutoToolChangNcM);
Line(sb, 1, "粗公自动换刀NC", "AutoToolChangNcR", data.AutoToolChangNcR);
Line(sb, 1, "电极头检测尺寸", "DetectionSize", data.DetectionSize);
Line(sb, 1, "电极基准面Z值", "ReferencePlaneZval", data.ReferencePlaneZval);
Line(sb, 1, "程序单生成时间", "CreatTime", data.CreatTime);
Line(sb, 1, "工件号", "PieceNumber", data.PieceNumber);
Line(sb, 1, "精公二维码", "CellBarCodeF", data.CellBarCodeF);
Line(sb, 1, "中公二维码", "CellBarCodeM", data.CellBarCodeM);
Line(sb, 1, "粗公二维码", "CellBarCodeR", data.CellBarCodeR);
Line(sb, 1, "分中Z轴取数方式", "ZType", data.ZType);
Line(sb, 1, "是否旋转工件", "NcRotate", data.NcRotate);
Line(sb, 1, "旋转角度", "NcAngle", data.NcAngle);
Line(sb, 1, "是否镜像工件", "NcMirror", data.NcMirror);
Line(sb, 1, "镜像参考平面", "NcAxis", data.NcAxis);
if (data.ProjectData != null)
{
var pd = data.ProjectData;
sb.AppendLine(" [项目 ProjectData]");
Line(sb, 2, "项目名称", "Project", pd.Project);
Line(sb, 2, "项目路径", "PDSession", pd.PDSession);
Line(sb, 2, "NC输出路径", "NcprogramPath", pd.NcprogramPath);
Line(sb, 2, "项目总时长", "TotalTime", pd.TotalTime);
Line(sb, 2, "项目切削时长", "CutTime", pd.CutTime);
Line(sb, 2, "PD总时长(一般不用)", "PDTotalTime", pd.PDTotalTime);
Line(sb, 2, "PD切削时长(一般不用)", "PDCutTime", pd.PDCutTime);
}
else
{
sb.AppendLine(" [项目 ProjectData]: (null)");
}
if (data.PositionDataList == null || data.PositionDataList.Count == 0)
{
sb.AppendLine(" [工位列表]: (空)");
}
else
{
for (int i = 0; i < data.PositionDataList.Count; i++)
{
AppendPosition(sb, i, data.PositionDataList[i]);
}
}
AppendExtension(sb, 1, data.ExtensionData);
return sb.ToString();
}
private static void AppendPosition(StringBuilder sb, int index, PositionData pos)
{
if (pos == null)
{
sb.AppendLine(string.Format(" [工位 {0}]: (null)", index));
return;
}
sb.AppendLine(string.Format(" [工位 {0}] {1}", index, pos.PositionName ?? "(unnamed)"));
Line(sb, 2, "工位名称", "PositionName", pos.PositionName);
Line(sb, 2, "毛坯最大Z", "StartBlockMaxZ", pos.StartBlockMaxZ);
Line(sb, 2, "工位总时长", "PositionTotalTime", pos.PositionTotalTime);
Line(sb, 2, "工位切削时长", "PositionCutTime", pos.PositionCutTime);
Line(sb, 2, "基准角", "DatumMark", pos.DatumMark);
Line(sb, 2, "订料尺寸", "BlockSizeString", pos.BlockSizeString);
Line(sb, 2, "模型尺寸", "ModelSizeByPosition", pos.ModelSizeByPosition);
Line(sb, 2, "毛料尺寸", "BlockSizeByPosition", pos.BlockSizeByPosition);
if (pos.ConfigSetupSheet != null)
{
var cfg = pos.ConfigSetupSheet;
sb.AppendLine(" [界面配置 ConfigSetupSheet]");
Line(sb, 3, "客户", "Customers", cfg.Customers);
Line(sb, 3, "机床", "MachineNo", cfg.MachineNo);
Line(sb, 3, "材质", "Material", cfg.Material);
Line(sb, 3, "模号", "MouldNo", cfg.MouldNo);
Line(sb, 3, "工件名称", "PieceName", cfg.PieceName);
Line(sb, 3, "员工", "EmployeeName", cfg.EmployeeName);
Line(sb, 3, "装夹", "ClampType", cfg.ClampType);
AppendExtension(sb, 3, cfg.ExtensionData);
}
if (pos.ImageBytesList == null || pos.ImageBytesList.Count == 0)
{
sb.AppendLine(" 预览图(ImageBytesList): 0 张");
}
else
{
sb.AppendLine(string.Format(" 预览图(ImageBytesList): 共 {0} 张", pos.ImageBytesList.Count));
for (int ii = 0; ii < pos.ImageBytesList.Count; ii++)
{
byte[] bytes = pos.ImageBytesList[ii];
int len = bytes == null ? 0 : bytes.Length;
sb.AppendLine(string.Format(" 第 {0} 张: {1} 字节", ii, len));
}
}
if (pos.ToolPathList == null || pos.ToolPathList.Count == 0)
{
sb.AppendLine(" [刀路列表]: (空)");
}
else
{
for (int ti = 0; ti < pos.ToolPathList.Count; ti++)
{
AppendToolPath(sb, ti, pos.ToolPathList[ti]);
}
}
AppendExtension(sb, 2, pos.ExtensionData);
}
private static void AppendToolPath(StringBuilder sb, int index, ToolPathData tp)
{
if (tp == null)
{
sb.AppendLine(string.Format(" [刀路 {0}]: (null)", index));
return;
}
sb.AppendLine(string.Format(" [刀路 {0}] {1}", index, tp.Toolpath ?? "(unnamed)"));
Line(sb, 3, "串联坐标", "NcWpName", tp.NcWpName);
Line(sb, 3, "NC名称", "Ncprogram", tp.Ncprogram);
Line(sb, 3, "刀路名称", "Toolpath", tp.Toolpath);
Line(sb, 3, "刀具名称", "ToolID", tp.ToolID);
Line(sb, 3, "刀尖类型", "ToolType", tp.ToolType);
Line(sb, 3, "刀具直径", "Dia", tp.Dia);
Line(sb, 3, "刀尖圆角", "Tip", tp.Tip);
Line(sb, 3, "伸出长度", "Overhang", tp.Overhang);
Line(sb, 3, "刀路Z最小", "TPZMin", tp.TPZMin);
Line(sb, 3, "旧版转速", "Spindle", tp.Spindle);
Line(sb, 3, "旧版进给", "Cut", tp.Cut);
Line(sb, 3, "公差", "Tol", tp.Tol);
Line(sb, 3, "总时间", "Totaltime", tp.Totaltime);
Line(sb, 3, "切削时间", "CutTime", tp.CutTime);
Line(sb, 3, "径向余量", "Thickness", tp.Thickness);
Line(sb, 3, "轴向余量", "AxialThickness", tp.AxialThickness);
Line(sb, 3, "碰撞检测", "CollChecked", tp.CollChecked);
Line(sb, 3, "刀号", "ToolNumber", tp.ToolNumber);
Line(sb, 3, "NC描述", "Description", tp.Description);
Line(sb, 3, "刃长", "Len", tp.Len);
Line(sb, 3, "锥度直径", "TaperDiameter", tp.TaperDiameter);
Line(sb, 3, "刀具锥度", "TaperAngle", tp.TaperAngle);
Line(sb, 3, "行距", "Stepover", tp.Stepover);
Line(sb, 3, "步距", "Stepdown", tp.Stepdown);
Line(sb, 3, "NC备注", "NcprogramNotes", tp.NcprogramNotes);
Line(sb, 3, "刀具描述", "ToolDescription", tp.ToolDescription);
Line(sb, 3, "进给(FeedRateRapid)", "FeedRateRapid", tp.FeedRateRapid);
Line(sb, 3, "刀头最大", "THUpper", tp.THUpper);
Line(sb, 3, "刀柄最大", "TSUpper", tp.TSUpper);
Line(sb, 3, "刀头最小", "THLower", tp.THLower);
Line(sb, 3, "刀柄最小", "TSLower", tp.TSLower);
Line(sb, 3, "刀路坐标", "WKPLName", tp.WKPLName);
Line(sb, 3, "刀头名称", "HolderName", tp.HolderName);
Line(sb, 3, "刀具格式名", "Tool", tp.Tool);
Line(sb, 3, "刀具备注", "ToolNote", tp.ToolNote);
Line(sb, 3, "加工深度", "Depth", tp.Depth);
Line(sb, 3, "刀路备注", "ToolpathNotes", tp.ToolpathNotes);
Line(sb, 3, "NC路径", "NcprogramPath", tp.NcprogramPath);
Line(sb, 3, "上圆角", "UpperTip", tp.UpperTip);
Line(sb, 3, "刀柄名称", "ShankName", tp.ShankName);
Line(sb, 3, "加长杆名称", "ExtensionName", tp.ExtensionName);
Line(sb, 3, "加长杆长度", "ExtensionLength", tp.ExtensionLength);
Line(sb, 3, "刀柄长度", "ShankLength", tp.ShankLength);
Line(sb, 3, "刀头加长杆刀柄", "HolderExtensioShank", tp.HolderExtensioShank);
Line(sb, 3, "刀头加长杆", "HolderExtensio", tp.HolderExtensio);
Line(sb, 3, "安全高度", "SafeZ", tp.SafeZ);
Line(sb, 3, "半径补偿编码", "CompCode", tp.CompCode);
Line(sb, 3, "启用半径补偿", "RadiusCompNumber_Active", tp.RadiusCompNumber_Active);
Line(sb, 3, "半径补偿号", "RadiusCompNumber_Value", tp.RadiusCompNumber_Value);
Line(sb, 3, "夹持名称", "OldHolderName", tp.OldHolderName);
Line(sb, 3, "刀具半径补偿", "CncCutterCompensationActive", tp.CncCutterCompensationActive);
Line(sb, 3, "NC文件大小", "NcFileSize", tp.NcFileSize);
Line(sb, 3, "NC输出坐标系", "NcWorkplane", tp.NcWorkplane);
Line(sb, 3, "切削长度", "CutLength", tp.CutLength);
Line(sb, 3, "标题", "Title", tp.Title);
Line(sb, 3, "刀具寿命", "ToolLife", tp.ToolLife);
Line(sb, 3, "TPXmax", "TPXmax", tp.TPXmax);
Line(sb, 3, "TPXmin", "TPXmin", tp.TPXmin);
Line(sb, 3, "TPYmax", "TPYmax", tp.TPYmax);
Line(sb, 3, "TPYmin", "TPYmin", tp.TPYmin);
Line(sb, 3, "TPZmax", "TPZmax", tp.TPZmax);
Line(sb, 3, "TPZmin", "TPZmin", tp.TPZmin);
Line(sb, 3, "标距长度", "GaugeLength", tp.GaugeLength);
Line(sb, 3, "策略类型", "Strategy", tp.Strategy);
Line(sb, 3, "钻孔径向余量", "DrillThickness", tp.DrillThickness);
Line(sb, 3, "钻孔轴向余量", "DrillAxialThickness", tp.DrillAxialThickness);
Line(sb, 3, "刀路径向余量", "TpThickness", tp.TpThickness);
Line(sb, 3, "刀路轴向余量", "TpAxialThickness", tp.TpAxialThickness);
Line(sb, 3, "钻孔深度类型", "DrillDepthType", tp.DrillDepthType);
Line(sb, 3, "钻孔深度用户定义", "DrillDepthUserDefined", tp.DrillDepthUserDefined);
Line(sb, 3, "转速", "Rpm", tp.Rpm);
Line(sb, 3, "进给", "Frate", tp.Frate);
Line(sb, 3, "钻孔循环类型", "DrillType", tp.DrillType);
Line(sb, 3, "啄孔深度", "PeckDepth", tp.PeckDepth);
Line(sb, 3, "不合并NC", "NoMerge", tp.NoMerge);
if (tp.ToolHolders != null && tp.ToolHolders.Count > 0)
{
sb.AppendLine(string.Format(" 刀头几何(ToolHolders): {0} 段", tp.ToolHolders.Count));
for (int i = 0; i < tp.ToolHolders.Count; i++)
AppendHolder(sb, "刀头", i, tp.ToolHolders[i]);
}
if (tp.ToolShanks != null && tp.ToolShanks.Count > 0)
{
sb.AppendLine(string.Format(" 刀柄几何(ToolShanks): {0} 段", tp.ToolShanks.Count));
for (int i = 0; i < tp.ToolShanks.Count; i++)
AppendHolder(sb, "刀柄", i, tp.ToolShanks[i]);
}
if (tp.TpSizeList != null && tp.TpSizeList.Count > 0)
{
sb.AppendLine(string.Format(" 刀路尺寸列表(TpSizeList): {0}", tp.TpSizeList.Count));
for (int i = 0; i < tp.TpSizeList.Count; i++)
Line(sb, 4, "尺寸[" + i + "]", "TpSizeList", tp.TpSizeList[i]);
}
if (tp.NcCodeList != null && tp.NcCodeList.Count > 0)
{
Line(sb, 3, "串联二维码", "NcCodeList", string.Join("; ", tp.NcCodeList));
}
AppendExtension(sb, 3, tp.ExtensionData);
}
private static void AppendHolder(StringBuilder sb, string kind, int index, HolderOrShank h)
{
if (h == null)
{
sb.AppendLine(string.Format(" {0}[{1}]: (null)", kind, index));
return;
}
sb.AppendLine(string.Format(" {0}[{1}]: 上径={2} 下径={3} 长={4}",
kind, index, h.UpperDiameter, h.LowerDiameter, h.Length));
}
private static void AppendExtension(StringBuilder sb, int indent, IDictionary ext)
{
if (ext == null || ext.Count == 0) return;
string pad = new string(' ', indent * 2);
sb.AppendLine(pad + "[扩展字段 ExtensionData]");
foreach (var kv in ext)
{
string val = kv.Value == null ? "(null)" : kv.Value.ToString(Newtonsoft.Json.Formatting.None);
if (val.Length > 200) val = val.Substring(0, 200) + "...(截断)";
sb.AppendLine(string.Format("{0} {1}: {2}", pad, kv.Key, val));
}
}
private static void Line(StringBuilder sb, int indent, string cn, string en, object value)
{
string pad = new string(' ', indent * 2);
string text;
if (value == null) text = "(null)";
else if (value is string) text = (string)value;
else text = Convert.ToString(value, System.Globalization.CultureInfo.InvariantCulture);
sb.AppendLine(string.Format("{0}{1}({2}): {3}", pad, cn, en, text));
}
public static void PrintPlainText(SetupsheetData data)
{
Console.WriteLine(ToPlainText(data));
}
public static string SavePlainText(SetupsheetData data, string txtPath)
{
string text = ToPlainText(data);
File.WriteAllText(txtPath, text, new UTF8Encoding(false));
return txtPath;
}
public static void PrintSummary(SetupsheetData data)
{
if (data == null)
{
Console.WriteLine(" (无对象)");
return;
}
string project = data.ProjectData != null ? data.ProjectData.Project : null;
string session = data.ProjectData != null ? data.ProjectData.PDSession : null;
Console.WriteLine(" ---- SetupsheetData 对象摘要 ----");
Console.WriteLine(" PieceNumber : {0}", data.PieceNumber ?? "(null)");
Console.WriteLine(" Project : {0}", project ?? "(null)");
Console.WriteLine(" PDSession : {0}", session ?? "(null)");
Console.WriteLine(" CreatTime : {0}", data.CreatTime ?? "(null)");
Console.WriteLine(" NcWpName : {0}", data.NcWpName ?? "(null)");
if (data.ProjectData != null)
{
Console.WriteLine(" TotalTime : {0}", data.ProjectData.TotalTime);
Console.WriteLine(" CutTime : {0}", data.ProjectData.CutTime);
}
Console.WriteLine(" 工位数 : {0}", data.PositionCount);
if (data.PositionDataList != null)
{
for (int i = 0; i < data.PositionDataList.Count; i++)
{
var pos = data.PositionDataList[i];
if (pos == null)
{
Console.WriteLine(" [{0}] (null)", i);
continue;
}
int img = pos.ImageBytesList == null ? 0 : pos.ImageBytesList.Count(b => b != null && b.Length > 0);
Console.WriteLine(" [{0}] {1} 刀路={2} 预览图={3} 订料={4}",
i,
pos.PositionName ?? "(unnamed)",
pos.ToolPathCount,
img,
pos.BlockSizeString ?? "");
if (pos.ModelSizeByPosition != null)
Console.WriteLine(" 模型尺寸: {0}", pos.ModelSizeByPosition);
if (pos.ConfigSetupSheet != null)
{
var cfg = pos.ConfigSetupSheet;
Console.WriteLine(" 客户/机床/材质: {0} / {1} / {2}",
cfg.Customers ?? "-", cfg.MachineNo ?? "-", cfg.Material ?? "-");
}
}
}
int tpCount = data.EnumerateToolPaths().Count();
Console.WriteLine(" 刀路合计 : {0}", tpCount);
Console.WriteLine(" --------------------------------");
}
public static void PrintToolPaths(SetupsheetData data)
{
if (data == null)
{
Console.WriteLine(" (无对象)");
return;
}
int n = 0;
if (data.PositionDataList != null)
{
for (int pi = 0; pi < data.PositionDataList.Count; pi++)
{
var pos = data.PositionDataList[pi];
if (pos == null || pos.ToolPathList == null) continue;
for (int ti = 0; ti < pos.ToolPathList.Count; ti++)
{
var tp = pos.ToolPathList[ti];
if (tp == null) continue;
n++;
Console.WriteLine(" #{0} 工位[{1}]{2} {3}",
n, pi, pos.PositionName ?? "", tp);
Console.WriteLine(" 刀号={0} Tip={1} Overhang={2} Tol={3} 余量={4}/{5} 时间={6}",
tp.ToolNumber, tp.Tip, tp.Overhang, tp.Tol, tp.Thickness, tp.AxialThickness, tp.Totaltime);
}
}
}
if (n == 0) Console.WriteLine(" (无刀路)");
}
public static ToolPathData FindToolPath(SetupsheetData data, string keyword)
{
if (data == null || string.IsNullOrWhiteSpace(keyword)) return null;
keyword = keyword.Trim();
foreach (var tp in data.EnumerateToolPaths())
{
if (string.Equals(tp.Toolpath, keyword, StringComparison.OrdinalIgnoreCase)
|| string.Equals(tp.Ncprogram, keyword, StringComparison.OrdinalIgnoreCase)
|| string.Equals(tp.ToolID, keyword, StringComparison.OrdinalIgnoreCase)
|| string.Equals(tp.Tool, keyword, StringComparison.OrdinalIgnoreCase)
|| (!string.IsNullOrEmpty(tp.Toolpath) && tp.Toolpath.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) >= 0))
{
return tp;
}
}
return null;
}
public static void PrintToolPathDetail(ToolPathData tp)
{
if (tp == null)
{
Console.WriteLine(" (未找到)");
return;
}
Console.WriteLine(SerializeOne(tp));
}
public static int SavePreviewImages(SetupsheetData data, string outputDir)
{
if (data == null || data.PositionDataList == null) return 0;
Directory.CreateDirectory(outputDir);
int saved = 0;
for (int pi = 0; pi < data.PositionDataList.Count; pi++)
{
var pos = data.PositionDataList[pi];
if (pos == null || pos.ImageBytesList == null) continue;
for (int ii = 0; ii < pos.ImageBytesList.Count; ii++)
{
byte[] bytes = pos.ImageBytesList[ii];
if (bytes == null || bytes.Length == 0) continue;
string name = string.Format("pos{0}_{1}_img{2}.png",
pi,
SanitizeFileName(pos.PositionName ?? "pos"),
ii);
string path = Path.Combine(outputDir, name);
try
{
using (var ms = new MemoryStream(bytes))
using (Image img = Image.FromStream(ms))
{
img.Save(path, System.Drawing.Imaging.ImageFormat.Png);
}
saved++;
Console.WriteLine(" 已保存预览图: {0}", path);
}
catch (Exception ex)
{
string bin = Path.ChangeExtension(path, ".bin");
File.WriteAllBytes(bin, bytes);
saved++;
Console.WriteLine(" 非位图,已写原始字节: {0} ({1})", bin, ex.Message);
}
}
}
return saved;
}
public static string SanitizeFileName(string name)
{
if (string.IsNullOrEmpty(name)) return "x";
foreach (char c in Path.GetInvalidFileNameChars())
name = name.Replace(c, '_');
return name;
}
private static string SerializeOne(object obj)
{
return JsonConvert.SerializeObject(obj, JsonSettings);
}
public static void PrintHelp()
{
Console.WriteLine();
Console.WriteLine("控制台命令(对象还原后可用):");
Console.WriteLine(" help 显示本帮助");
Console.WriteLine(" summary 打印 Latest 对象摘要");
Console.WriteLine(" text 打印完整明文(中英对照),并可再落盘 .txt");
Console.WriteLine(" tools 列出全部刀路");
Console.WriteLine(" tool <关键字> 按刀路名/NC名/刀具名查找并打印 JSON");
Console.WriteLine(" positions 列出工位");
Console.WriteLine(" images 将预览图导出到 Received\\images_xxx\\");
Console.WriteLine(" dump 将对象重新序列化为 Received\\latest-object.json");
Console.WriteLine(" path 显示最近落盘的 JSON / 明文路径");
Console.WriteLine(" load [路径] 从 JSON 文件再次还原");
Console.WriteLine(" quit / exit 退出程序");
Console.WriteLine();
}
}
}