关于A = B.TryParse(C,out var D);语法

该代码示例解释了如何使用B.TryParse方法尝试将字符串C转换为B类型的值(这里是int)。如果转换成功,A为true且D被赋值为转换后的int值;否则,A为false,D为空。C全为数字时,D为123(int类型),含有非数字字符则转换失败,D无值。

这里的 A = B.TryParse(C,out var D)

A是一个bool变量 

B是类型(int,string...)

C是一个常量

D也是一个常量

用一个例子来详细解释一下

 假设:B为int类型,C是string类型 “123”

        这行代码的含义是将 “C ”值尝试转成 int 类型,这里“C”是string类型,只有C全是数字才可以转换成功,即这里的“A”是bool值,但是由于用到了“out”关键字,返回值必须进行赋值,所以如果转换成功,即A为true,将D进行赋值为int.Parse(C)后返回,id为int类型。如果A为false,那么D是空的。所以,这行返回一个 bool类型 A , 还有一个将string类型转换成int类型的C,这个就是int类型D的值。

所以C如果全是数字的话,A为true,D就是“123”转化过来的(int)123。

如果C中有字符字母等,转换不成功,那么A为false,D是一个空值。

主要看B的类型区分。

using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.Colors; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Runtime; using Autodesk.AutoCAD.Windows; using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Windows.Forms; using static Autodesk.AutoCAD.LayerManager.LayerFilter; using Application = Autodesk.AutoCAD.ApplicationServices.Application; using DialogResult = System.Windows.Forms.DialogResult; using Exception = Autodesk.AutoCAD.Runtime.Exception; using SaveFileDialog = System.Windows.Forms.SaveFileDialog; namespace QuadProcessor { public class QuadProcessor { [CommandMethod("PROCESSQUADS", CommandFlags.Modal)] public void ProcessQuads() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; try { // 选择四边形(LWPOLYLINE) PromptSelectionResult selRes = ed.GetSelection(new SelectionFilter( new[] { new TypedValue(0, "LWPOLYLINE") })); if (selRes.Status != PromptStatus.OK) { ed.WriteMessage("\n操作已取消。"); return; } int totalCount = selRes.Value.Count; int processedCount = 0; int skippedCount = 0; var results = new List<QuadResult>(); // 使用句柄作为键 var errors = new Dictionary<string, string>(); var skipReasons = new Dictionary<string, string>(); Stopwatch sw = Stopwatch.StartNew(); ObjectId[] ids = selRes.Value.GetObjectIds(); // 获取排序选项 var sortOption = GetSortOption(ed); if (sortOption == null) return; // 用户取消 // 使用文档锁确保线程安全 using (DocumentLock docLock = doc.LockDocument()) using (Transaction tr = db.TransactionManager.StartTransaction()) { // 单线程处理所有选择的四边形 for (int i = 0; i < ids.Length; i++) { ObjectId id = ids[i]; string handle = id.Handle.ToString(); try { Polyline pl = tr.GetObject(id, OpenMode.ForRead) as Polyline; if (pl != null) { if (pl.NumberOfVertices == 4 && pl.Closed) { string skipReason; string textContent = GetTextInsidePolyline(tr, pl); var result = ProcessQuad(pl, out skipReason, textContent, i + 1); if (result != null) { results.Add(result); processedCount++; } else { skippedCount++; skipReasons[handle] = skipReason ?? "未知原因跳过"; } } else { skippedCount++; skipReasons[handle] = "不是四边形(顶点数不为4或未闭合)"; } } else { skippedCount++; skipReasons[handle] = "所选对象不是多段线"; } } catch (Exception ex) { errors[handle] = $"处理失败: {ex.Message}"; } } tr.Commit(); } // 这里会自动解锁文档 // 按用户选择的排序方式排序结果 SortResults(results, sortOption.Value); // 获取默认桌面路径 string defaultPath = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "InformationExport.csv"); // 显示保存文件对话框 string csvPath = ShowSaveFileDialog(defaultPath); if (csvPath != null) { // 导出结果 ExportToCSV(results, csvPath); // 显示统计信息 ed.WriteMessage($"\n处理完成: " + $"\n总四边形数: {totalCount} " + $"\n成功处理: {processedCount} " + $"\n跳过: {skippedCount} " + $"\n错误: {errors.Count} " + $"\n耗时: {sw.Elapsed.TotalSeconds:F2}秒" + $"\n结果已保存至: {csvPath}"); // 询问是否打开文件 ed.WriteMessage("\n\n**********************************************"); ed.WriteMessage("\n* 是否打开结果文件? [是(Y)/否(N)] <是>: *"); ed.WriteMessage("\n**********************************************"); PromptKeywordOptions openOptions = new PromptKeywordOptions(""); openOptions.Keywords.Add("是", "Y", "Y"); openOptions.Keywords.Add("否", "N", "N"); openOptions.Keywords.Default = "是"; openOptions.AllowNone = true; PromptResult openRes = ed.GetKeywords(openOptions); if (openRes.Status == PromptStatus.OK && openRes.StringResult == "是") { try { Process.Start(new ProcessStartInfo(csvPath) { UseShellExecute = true }); } catch (Exception ex) { ed.WriteMessage($"\n打开文件失败: {ex.Message}"); } } // 询问是否在CAD中插入结果表格 PromptKeywordOptions tableOptions = new PromptKeywordOptions("\n是否在CAD图中插入结果表格? [是(Y)/否(N)] <是>: "); tableOptions.Keywords.Add("是", "Y", "Y"); tableOptions.Keywords.Add("否", "N", "N"); tableOptions.Keywords.Default = "是"; tableOptions.AllowNone = true; PromptResult tableRes = ed.GetKeywords(tableOptions); if (tableRes.Status == PromptStatus.OK && tableRes.StringResult == "是") { // 提示用户指定表格插入点 PromptPointResult ppr = ed.GetPoint("\n指定表格插入点: "); if (ppr.Status == PromptStatus.OK) { using (Transaction tr = db.TransactionManager.StartTransaction()) { InsertResultsTable(tr, results, ppr.Value); tr.Commit(); ed.WriteMessage("\n结果表格已插入到图中。"); } } } } else { ed.WriteMessage("\n操作已取消,未保存结果。"); } // 错误日志记录 if (errors.Count > 0 || skipReasons.Count > 0) { string logDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); string logFileName = $"gs_{DateTime.Now:yyyyMMddHHmmss}.log"; string logPath = Path.Combine(logDir, logFileName); using (StreamWriter logWriter = new StreamWriter(logPath)) { logWriter.WriteLine($"四边形处理日志 - {DateTime.Now}"); logWriter.WriteLine("================================="); if (errors.Count > 0) { logWriter.WriteLine("\n错误详情:"); foreach (var error in errors) { logWriter.WriteLine($"句柄 {error.Key}: {error.Value}"); } } if (skipReasons.Count > 0) { logWriter.WriteLine("\n跳过详情:"); foreach (var skip in skipReasons) { logWriter.WriteLine($"句柄 {skip.Key}: {skip.Value}"); } } } ed.WriteMessage($"\n详细错误和跳过信息已保存至: {logPath}"); } // 显示错误信息 if (errors.Count > 0) { ed.WriteMessage("\n\n错误详情:"); foreach (var error in errors) { ed.WriteMessage($"\n句柄 {error.Key}: {error.Value}"); } } // 显示跳过信息 if (skipReasons.Count > 0) { ed.WriteMessage("\n\n跳过详情:"); foreach (var skip in skipReasons) { ed.WriteMessage($"\n句柄 {skip.Key}: {skip.Value}"); } } } catch (Exception ex) { ed.WriteMessage($"\n错误: {ex.Message}"); } } // 在CAD中插入结果表格 (修复版本) private void InsertResultsTable(Transaction tr, List<QuadResult> results, Point3d insertionPoint) { try { Database db = Application.DocumentManager.MdiActiveDocument.Database; // 创建表格 Table table = new Table(); table.TableStyle = db.Tablestyle; // 使用当前表格样式 table.SetSize(results.Count + 1, 13); // 行数:结果行数+标题行,列数:13 table.Position = insertionPoint; // 设置行高和文本高度 for (int i = 0; i <= results.Count; i++) { table.SetRowHeight(i, i == 0 ? 15 : 10); table.SetTextHeight(i, i == 0 ? 4 : 3.5); } // 设置单元格边距 for (int row = 0; row <= results.Count; row++) { for (int col = 0; col < 13; col++) { table.Cells[row, col].HorizontalMargin = 1; table.Cells[row, col].VerticalMargin = 1; } } // 设置标题行 string[] headers = { "序号", "对象句柄", "图形编号", "边1", "边2", "边3", "边4", "对角线1", "对角线2", "最小外接矩形宽度", "最小外接矩形高度", "中心点X", "中心点Y" }; for (int col = 0; col < headers.Length; col++) { table.Cells[0, col].TextString = headers[col]; table.Cells[0, col].Alignment = CellAlignment.MiddleCenter; table.Cells[0, col].BackgroundColor = Color.FromColorIndex(ColorMethod.ByAci, 253); // 浅灰色背景 table.Cells[0, col].BorderColor = Color.FromColorIndex(ColorMethod.ByAci, 0); // 黑色边框 } // 填充数据行 for (int row = 0; row < results.Count; row++) { QuadResult r = results[row]; table.Cells[row + 1, 0].TextString = r.SequenceNumber.ToString(); table.Cells[row + 1, 1].TextString = r.Handle; table.Cells[row + 1, 2].TextString = r.TextContent; table.Cells[row + 1, 3].TextString = r.Side1.ToString("F0"); table.Cells[row + 1, 4].TextString = r.Side2.ToString("F0"); table.Cells[row + 1, 5].TextString = r.Side3.ToString("F0"); table.Cells[row + 1, 6].TextString = r.Side4.ToString("F0"); table.Cells[row + 1, 7].TextString = r.Diagonal1.ToString("F0"); table.Cells[row + 1, 8].TextString = r.Diagonal2.ToString("F0"); table.Cells[row + 1, 9].TextString = r.OBBWidth.ToString("F0"); table.Cells[row + 1, 10].TextString = r.OBBHeight.ToString("F0"); table.Cells[row + 1, 11].TextString = r.CenterX.ToString("F0"); table.Cells[row + 1, 12].TextString = r.CenterY.ToString("F0"); // 设置数据对齐方式 for (int col = 0; col < 13; col++) { table.Cells[row + 1, col].Alignment = CellAlignment.MiddleCenter; table.Cells[row + 1, col].BorderColor = Color.FromColorIndex(ColorMethod.ByAci, 0); // 黑色边框 } } // 设置列宽 double[] columnWidths = { 8, 15, 15, 8, 8, 8, 8, 10, 10, 15, 15, 12, 12 }; for (int col = 0; col < columnWidths.Length; col++) { table.Columns[col].Width = columnWidths[col]; } // 添加到模型空间 BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable; BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord; btr.AppendEntity(table); tr.AddNewlyCreatedDBObject(table, true); } catch (Exception ex) { Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage($"\n插入表格失败: {ex.Message}"); } } private SortOption? GetSortOption(Editor ed) { var options = new PromptKeywordOptions("\n选择排序方式 [图形编号(G)/选择顺序(S)/坐标位置(C)/序号(N)] <图形编号>: "); // 添加关键字和别名 options.Keywords.Add("图形编号", "G", "G"); options.Keywords.Add("选择顺序", "S", "S"); options.Keywords.Add("坐标位置", "C", "C"); options.Keywords.Add("序号", "N", "N"); options.Keywords.Default = "图形编号"; options.AllowNone = true; var res = ed.GetKeywords(options); if (res.Status != PromptStatus.OK) return null; // 根据用户输入返回排序选项 switch (res.StringResult) { case "图形编号": case "G": return SortOption.TextID; case "选择顺序": case "S": return SortOption.SelectionOrder; case "坐标位置": case "C": return SortOption.Coordinate; case "序号": case "N": return SortOption.SequenceNumber; default: return SortOption.TextID; } } private void SortResults(List<QuadResult> results, SortOption sortOption) { switch (sortOption) { case SortOption.SequenceNumber: break; case SortOption.SelectionOrder: break; case SortOption.Coordinate: results.Sort((a, b) => { int cmp = a.CenterX.CompareTo(b.CenterX); return cmp != 0 ? cmp : a.CenterY.CompareTo(b.CenterY); }); break; case SortOption.TextID: results.Sort(new NaturalStringComparer()); break; } // 排序后重新设置序号 for (int i = 0; i < results.Count; i++) { results[i].SequenceNumber = i + 1; } } // 自然排序比较器 public class NaturalStringComparer : IComparer<QuadResult> { public int Compare(QuadResult x, QuadResult y) { if (x == null && y == null) return 0; if (x == null) return -1; if (y == null) return 1; return CompareNatural(x.TextContent, y.TextContent); } private int CompareNatural(string strA, string strB) { if (strA == null && strB == null) return 0; if (strA == null) return -1; if (strB == null) return 1; int indexA = 0; int indexB = 0; while (indexA < strA.Length && indexB < strB.Length) { if (char.IsDigit(strA[indexA]) && char.IsDigit(strB[indexB])) { string numStrA = ExtractNumber(strA, ref indexA); string numStrB = ExtractNumber(strB, ref indexB); if (int.TryParse(numStrA, out int numA) && int.TryParse(numStrB, out int numB)) { int numCompare = numA.CompareTo(numB); if (numCompare != 0) return numCompare; } else { int strCompare = string.Compare(numStrA, numStrB, StringComparison.Ordinal); if (strCompare != 0) return strCompare; } } else { int charCompare = strA[indexA].CompareTo(strB[indexB]); if (charCompare != 0) return charCompare; indexA++; indexB++; } } return strA.Length.CompareTo(strB.Length); } private string ExtractNumber(string str, ref int index) { int start = index; while (index < str.Length && char.IsDigit(str[index])) { index++; } return str.Substring(start, index - start); } } private string ShowSaveFileDialog(string defaultPath) { try { SaveFileDialog saveDialog = new SaveFileDialog { Title = "导出四边形分析结果", Filter = "CSV文件 (*.csv)|*.csv|所有文件 (*.*)|*.*", FileName = Path.GetFileName(defaultPath), InitialDirectory = Path.GetDirectoryName(defaultPath), DefaultExt = ".csv", AddExtension = true }; IntPtr acadWindow = Application.MainWindow.Handle; if (acadWindow != IntPtr.Zero) { System.Windows.Forms.IWin32Window owner = new WindowWrapper(acadWindow); if (saveDialog.ShowDialog(owner) == DialogResult.OK) { return saveDialog.FileName; } } else { if (saveDialog.ShowDialog() == DialogResult.OK) { return saveDialog.FileName; } } } catch (Exception) { return defaultPath; } return null; } private string GetTextInsidePolyline(Transaction tr, Polyline pl) { try { Extents3d extents = pl.GeometricExtents; Point3d minPoint = extents.MinPoint; Point3d maxPoint = extents.MaxPoint; Point3dCollection points = new Point3dCollection { minPoint, new Point3d(maxPoint.X, minPoint.Y, minPoint.Z), maxPoint, new Point3d(minPoint.X, maxPoint.Y, minPoint.Z), minPoint }; TypedValue[] filterList = new TypedValue[] { new TypedValue(0, "TEXT,MTEXT") }; SelectionFilter filter = new SelectionFilter(filterList); PromptSelectionResult selRes = Application.DocumentManager.MdiActiveDocument.Editor.SelectCrossingPolygon(points, filter); if (selRes.Status == PromptStatus.OK) { SelectionSet selectionSet = selRes.Value; List<TextInfo> textInfos = new List<TextInfo>(); foreach (SelectedObject selectedObject in selectionSet) { using (DBObject dbObj = tr.GetObject(selectedObject.ObjectId, OpenMode.ForRead)) { Point3d position = Point3d.Origin; string text = ""; if (dbObj is DBText dbText) { position = dbText.Position; text = dbText.TextString; } else if (dbObj is MText mText) { position = mText.Location; text = mText.Text; } if (!string.IsNullOrEmpty(text)) { textInfos.Add(new TextInfo { Position = position, Text = text, DistanceToCenter = GetDistanceToPolylineCenter(pl, position) }); } } } if (textInfos.Count == 0) return ""; var closestText = textInfos.OrderBy(t => t.DistanceToCenter).First(); return closestText.Text; } } catch { } return ""; } private double GetDistanceToPolylineCenter(Polyline pl, Point3d point) { double centerX = 0, centerY = 0; for (int i = 0; i < 4; i++) { Point2d pt = pl.GetPoint2dAt(i); centerX += pt.X; centerY += pt.Y; } centerX /= 4; centerY /= 4; double dx = point.X - centerX; double dy = point.Y - centerY; return Math.Sqrt(dx * dx + dy * dy); } private Point2d[] ReorderVertices(Polyline pl, out string error) { error = null; try { Point2d[] points = new Point2d[4]; for (int i = 0; i < 4; i++) points[i] = pl.GetPoint2dAt(i); var sortedByX = points.OrderBy(p => p.X).ToArray(); Point2d[] minXPoints = new Point2d[] { sortedByX[0], sortedByX[1] }; var sortedMinX = minXPoints.OrderBy(p => p.Y).ToArray(); Point2d bottomLeft = sortedMinX[0]; Point2d topLeft = sortedMinX[1]; Point2d[] remainingPoints = points.Except(minXPoints).ToArray(); var sortedRemaining = remainingPoints.OrderBy(p => p.Y).ToArray(); Point2d bottomRight = sortedRemaining[0]; Point2d topRight = sortedRemaining[1]; return new Point2d[] { bottomLeft, bottomRight, topRight, topLeft }; } catch (Exception ex) { error = $"顶点排序失败: {ex.Message}"; return null; } } private QuadResult ProcessQuad(Polyline pl, out string skipReason, string textContent, int sequenceNumber) { skipReason = null; try { string error; Point2d[] pts = ReorderVertices(pl, out error); if (pts == null) { skipReason = error ?? "顶点排序失败"; return null; } if (pts.Length != 4) { skipReason = "顶点数不足4个"; return null; } double centerX = pts.Average(p => p.X); double centerY = pts.Average(p => p.Y); double side1 = pts[0].GetDistanceTo(pts[1]); double side2 = pts[1].GetDistanceTo(pts[2]); double side3 = pts[2].GetDistanceTo(pts[3]); double side4 = pts[3].GetDistanceTo(pts[0]); double diag1 = pts[0].GetDistanceTo(pts[2]); double diag2 = pts[1].GetDistanceTo(pts[3]); var obb = CalculateOBB(pts, out error); if (obb == null) { skipReason = error ?? "无法计算最小外接矩形"; return null; } return new QuadResult( sequenceNumber, pl.ObjectId, textContent, side1, side2, side3, side4, diag1, diag2, obb.Width, obb.Height, centerX, centerY); } catch (Exception ex) { skipReason = $"处理失败: {ex.Message}"; return null; } } private OBBResult CalculateOBB(Point2d[] points, out string error) { error = null; try { var hull = CalculateConvexHull(points); if (hull == null || hull.Count < 3) { error = "无法计算凸包"; return null; } double minArea = double.MaxValue; double width = 0, height = 0; int hullCount = hull.Count; if (hullCount == 3) { return ProcessTriangle(hull); } for (int i = 0; i < hullCount; i++) { Vector2d edge = hull[(i + 1) % hullCount] - hull[i]; double edgeLength = edge.Length; if (edgeLength < 1e-9) continue; Vector2d edgeDir = edge / edgeLength; double angle = Math.Atan2(edgeDir.Y, edgeDir.X); Matrix2d rot = Matrix2d.Rotation(-angle, Point2d.Origin); double minX = double.MaxValue, maxX = double.MinValue; double minY = double.MaxValue, maxY = double.MinValue; for (int j = 0; j < hullCount; j++) { Point2d rotatedPt = hull[j].TransformBy(rot); if (rotatedPt.X < minX) minX = rotatedPt.X; if (rotatedPt.X > maxX) maxX = rotatedPt.X; if (rotatedPt.Y < minY) minY = rotatedPt.Y; if (rotatedPt.Y > maxY) maxY = rotatedPt.Y; } double w = maxX - minX; double h = maxY - minY; double area = w * h; if (area < minArea) { minArea = area; width = w; height = h; } } return new OBBResult(width, height); } catch (Exception ex) { error = $"OBB计算失败: {ex.Message}"; return null; } } private List<Point2d> CalculateConvexHull(Point2d[] points) { try { if (points.Length < 3) return new List<Point2d>(points); var sortedPoints = points.OrderBy(p => p.X).ThenBy(p => p.Y).ToArray(); List<Point2d> lowerHull = new List<Point2d>(); for (int i = 0; i < sortedPoints.Length; i++) { while (lowerHull.Count >= 2 && Cross(lowerHull[lowerHull.Count - 2], lowerHull[lowerHull.Count - 1], sortedPoints[i]) <= 0) { lowerHull.RemoveAt(lowerHull.Count - 1); } lowerHull.Add(sortedPoints[i]); } List<Point2d> upperHull = new List<Point2d>(); for (int i = sortedPoints.Length - 1; i >= 0; i--) { while (upperHull.Count >= 2 && Cross(upperHull[upperHull.Count - 2], upperHull[upperHull.Count - 1], sortedPoints[i]) <= 0) { upperHull.RemoveAt(upperHull.Count - 1); } upperHull.Add(sortedPoints[i]); } if (lowerHull.Count > 0) lowerHull.RemoveAt(lowerHull.Count - 1); if (upperHull.Count > 0) upperHull.RemoveAt(upperHull.Count - 1); lowerHull.AddRange(upperHull); return lowerHull; } catch { return null; } } private OBBResult ProcessTriangle(List<Point2d> triangle) { double minArea = double.MaxValue; double width = 0, height = 0; for (int i = 0; i < 3; i++) { Vector2d edge = triangle[(i + 1) % 3] - triangle[i]; double edgeLength = edge.Length; if (edgeLength < 1e-9) continue; Vector2d edgeDir = edge / edgeLength; double angle = Math.Atan2(edgeDir.Y, edgeDir.X); Matrix2d rot = Matrix2d.Rotation(-angle, Point2d.Origin); double minX = double.MaxValue, maxX = double.MinValue; double minY = double.MaxValue, maxY = double.MinValue; for (int j = 0; j < 3; j++) { Point2d rotatedPt = triangle[j].TransformBy(rot); if (rotatedPt.X < minX) minX = rotatedPt.X; if (rotatedPt.X > maxX) maxX = rotatedPt.X; if (rotatedPt.Y < minY) minY = rotatedPt.Y; if (rotatedPt.Y > maxY) maxY = rotatedPt.Y; } double w = maxX - minX; double h = maxY - minY; double area = w * h; if (area < minArea) { minArea = area; width = w; height = h; } } return new OBBResult(width, height); } private double Cross(Point2d a, Point2d b, Point2d c) { return (b.X - a.X) * (c.Y - a.Y) - (b.Y - a.Y) * (c.X - a.X); } private void ExportToCSV(IEnumerable<QuadResult> results, string path) { try { using (StreamWriter sw = new StreamWriter(path)) { sw.WriteLine("序号,对象句柄,图形编号,边1,边2,边3,边4,对角线1,对角线2,最小外接矩形宽度,最小外接矩形高度,中心点X,中心点Y"); foreach (var r in results) { sw.WriteLine($"{r.SequenceNumber}," + $"{r.Handle}," + $"\"{r.TextContent}\"," + $"{r.Side1:F0},{r.Side2:F0},{r.Side3:F0},{r.Side4:F0}," + $"{r.Diagonal1:F0},{r.Diagonal2:F0}," + $"{r.OBBWidth:F0},{r.OBBHeight:F0}," + $"{r.CenterX:F0},{r.CenterY:F0}"); } } } catch (Exception ex) { Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage( $"\n保存文件时出错: {ex.Message}"); } } } // 文字信息辅助类 public class TextInfo { public Point3d Position { get; set; } public string Text { get; set; } public double DistanceToCenter { get; set; } } // 排序选项枚举 public enum SortOption { TextID, SelectionOrder, Coordinate, SequenceNumber } // 结果数据结构 public class QuadResult { public int SequenceNumber { get; set; } public string Handle { get; } public string TextContent { get; } public double Side1 { get; } public double Side2 { get; } public double Side3 { get; } public double Side4 { get; } public double Diagonal1 { get; } public double Diagonal2 { get; } public double OBBWidth { get; } public double OBBHeight { get; } public double CenterX { get; } public double CenterY { get; } public QuadResult( int sequenceNumber, ObjectId objectId, string textContent, double side1, double side2, double side3, double side4, double diag1, double diag2, double width, double height, double centerX, double centerY) { SequenceNumber = sequenceNumber; Handle = objectId.Handle.ToString(); TextContent = textContent ?? ""; Side1 = side1; Side2 = side2; Side3 = side3; Side4 = side4; Diagonal1 = diag1; Diagonal2 = diag2; OBBWidth = width; OBBHeight = height; CenterX = centerX; CenterY = centerY; } } public class OBBResult { public double Width { get; } public double Height { get; } public OBBResult(double width, double height) { Width = width; Height = height; } } // 包装AutoCAD窗口的辅助类 public class WindowWrapper : System.Windows.Forms.IWin32Window { private readonly IntPtr _hwnd; public WindowWrapper(IntPtr handle) { _hwnd = handle; } public IntPtr Handle { get { return _hwnd; } } } }不改代码只修改错误 。不要有高级.语法
08-08
public class ReadOnlyBackgroundConverter : IValueConverter { // 定义共享的冻结画刷(线程安全,性能好) private static readonly Brush EnabledBrush = Brushes.White; // 可编辑时背景 private static readonly Brush DisabledBrush = new SolidColorBrush(Color.FromRgb(240, 240, 240)); // 灰色背景 static ReadOnlyBackgroundConverter() { // 冻结画刷以提升性能并支持跨线程访问 DisabledBrush.Freeze(); } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { // 如果 IsEnabled 为 false,返回灰色背景 if (value is bool isEnabled && !isEnabled) { return DisabledBrush; } // 否则返回正常背景(可编辑状态) return EnabledBrush; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotSupportedException("ReadOnlyBackgroundConverter 不支持反向转换。"); } } public class StepTextConverter : IMultiValueConverter { //public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) //{ // string verValue = System.Convert.ToString(values[0]); // string horValue = System.Convert.ToString(values[1]); // if (verValue == “{DependencyProperty.UnsetValue}” || verValue == “0”) // { // verValue = “”; // } // if (horValue == “{DependencyProperty.UnsetValue}” || horValue == “0”) // { // horValue = “”; // } // if (verValue == horValue) // { // return (Brush)Application.Current.Resources[“StepDefault”]; // } // return (Brush)Application.Current.Resources["StepHigh"]; //} public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { //处理 UnsetValue 或 null if (values[0] == null || values[0] == DependencyProperty.UnsetValue || values[1] == null || values[1] == DependencyProperty.UnsetValue) return Application.Current.Resources["StepHigh"]; var val1 = values[0]; var val2 = values[1]; // 提取可比较的数值(支持 bool -> 1/0, 数字字符串等) if (!TryConvertToNumericValue(val1, out double num1)) return Application.Current.Resources["StepHigh"]; if (!TryConvertToNumericValue(val2, out double num2)) return Application.Current.Resources["StepHigh"]; // 比较两个数值是否相等(允许微小浮点误差) const double epsilon = 1e-9; return Math.Abs(num1 - num2) < epsilon ? Application.Current.Resources["StepDefault"] : Application.Current.Resources["StepHigh"]; } private bool TryConvertToNumericValue(object value, out double result) { result = 0; if (value == null || value == DependencyProperty.UnsetValue) return false; // 先转成字符串用于分析(防止 ToString 被重写) string strValue = value.ToString()?.Trim(); if (string.IsNullOrEmpty(strValue)) return false; // 情况1:布尔值处理 if (bool.TryParse(strValue, out bool boolResult)) { result = boolResult ? 1.0 : 0.0; return true; } // 情况2:尝试解析为数值(支持各种格式) if (double.TryParse(strValue, NumberStyles.Any, CultureInfo.CurrentCulture, out double numResult) || double.TryParse(strValue, NumberStyles.Any, CultureInfo.InvariantCulture, out numResult)) { result = numResult; return true; } // 其他情况无法识别 return false; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { return null; } } 这两个能不能结合一下
12-16
using Newtonsoft.Json.Linq; using Sunny.UI; using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; // using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using System.Windows.Forms.DataVisualization.Charting; // using static System.Windows.Forms.VisualStyles.VisualStyleElement; namespace HHVideoPlayer.Model.ChartModel { public class ChartLib { public static void loadXY(LineChart chartdb, string path) { string savedate = Path.GetFileName(Path.GetDirectoryName(Path.GetDirectoryName(path))); //string rootDate = DateTime.ParseExact(savedate, "yyyy.MM.dd", CultureInfo.InvariantCulture); DateTime rootDate; if (!DateTime.TryParseExact(savedate, "yyyy.MM.dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out rootDate)) { rootDate = DateTime.Today; Debug.WriteLine($"解析失败{savedate}"); } DateTime baseDate = new DateTime(1899, 12, 30); List<string> Records = File.ReadLines(path).ToList(); int index = 0; // 移除索引过滤 foreach (var item in Records) { if (item.Contains(",")) { //DateTime x = DateTime.ParseExact(item.Split(",").First(), "HH:mm:ss.ffff", CultureInfo.InvariantCulture, DateTimeStyles.None); //chartdb.xDB.Add(x); string timePart = item.Split(",").First(); TimeSpan time = TimeSpan.ParseExact(timePart, "hh\\:mm\\:ss\\.ffff", CultureInfo.InvariantCulture); // 组合日期和时间 DateTime fullDateTime = baseDate.Add(time); chartdb.xDB.Add(fullDateTime); chartdb.yDB.Add(Convert.ToDouble(item.Split(",").Last())); } } chartdb.startTime = chartdb.xDB[0]; chartdb.endTime = chartdb.xDB[chartdb.xDB.Count - 1]; //Debug.WriteLine($"{chartdb.xDB[0]} --{chartdb.xDB[chartdb.xDB.Count-1]}"); return; } } public class ChartConfig { public string ChartName { get; set; } = "DefaultChart"; public string ChartTitle { get; set; } = "数据图表"; public Color SeriesColor { get; set; } = Color.Blue; public bool ScrollBarEnable { get; set; } = true; public int ScrollBarSize { get; set; } = 14; public double ViewSize { get; set; } = 60; // 默认显示60秒 } public class LineChart { public Chart Chart_ { get; } public String ShohType = "OverView"; // Follow or OverView public int _index = 0; public List<DateTime> xDB = new List<DateTime>(); public List<Double> yDB = new List<Double>(); public DateTime startTime; public DateTime endTime; public DateTime today=DateTime.Today; public System.Windows.Forms.Timer PlayTimer { get; } private bool _isPlaying = false; // 添加鼠标交互状态变量 private Point _dragStartPoint; private bool _isDragging; private double _startPosition; private double _startSize; // 1. 添加图表状态追踪变量 private bool _isViewValid = false; private bool _isDataLoaded = false; // 在LineChart类中添加新成员 private Label _lblXCoord; private Label _lblYCoord; public int PointIndex { get { return _index; } } public string PointXValue { get{ if (_index <= xDB.Count - 1)return xDB[_index].ToString("HH:mm:ss.ff"); else return "";} } public string PointYValue { get { if (_index <= yDB.Count - 1) return Math.Round(yDB[_index], 2).ToString(); else return ""; } } public LineChart(Chart chart, string showtype = "Follow") { Chart_ = chart; _index = 0; ShohType = showtype; InitChart(); InitCoordinateLabels(); PlayTimer = new System.Windows.Forms.Timer { Interval = 1 }; // 20 FPS (50ms) //Initialize(); BindFunc(); } private void BindFunc() { PlayTimer.Tick += (s, e) => PlayNextPoint(); // 绑定事件 // 启用鼠标事件 Chart_.MouseDown += Chart_MouseDown; Chart_.MouseMove += Chart_MouseMove; Chart_.MouseUp += Chart_MouseUp; Chart_.MouseWheel += Chart_MouseWheel; Chart_.Resize += Chart_Resize; //Chart_.AxisViewChanged += OnAxisViewChanged; //Chart_.AxisScrollBarClicked += OnScrollBarClicked; } public void InitChart() { CreateChart(); // 添加双缓冲支持(防止闪烁和空白) typeof(Chart).InvokeMember("DoubleBuffered", System.Reflection.BindingFlags.SetProperty | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, Chart_, new object[] { true }); // 添加安全刷新标记 _isViewValid = false; _isDataLoaded = false; // X轴滚动到最新位置 Chart_.ChartAreas[0].AxisX.ScaleView.Scroll(ScrollType.Last); // timer.Interval = 10; AddSeries("line", Color.Red); //Debug.WriteLine("InitChart"); } // 添加初始化标签的方法 private void InitCoordinateLabels() { // 创建X坐标标签 _lblXCoord = new Label { AutoSize = true, BackColor = Color.FromArgb(180, Color.White), ForeColor = Color.Blue, Font = new Font("Arial", 9, FontStyle.Bold), Location = new Point(10, 10), Text = "X: ", Padding = new Padding(3), Visible = true }; // 创建Y坐标标签 _lblYCoord = new Label { AutoSize = true, BackColor = Color.FromArgb(180, Color.White), ForeColor = Color.Red, Font = new Font("Arial", 9, FontStyle.Bold), Location = new Point(10, 35), Text = "Y: ", Padding = new Padding(3), Visible = true }; // 添加到图表控件 Chart_.Controls.Add(_lblXCoord); Chart_.Controls.Add(_lblYCoord); // 确保标签始终在最上层 _lblXCoord.BringToFront(); _lblYCoord.BringToFront(); } private void AddSeries(string seriersName, Color serierscolor) { Chart_.Series.Clear(); Series series = new Series(seriersName); //图表类型 设置为样条图曲线 //series.ChartType = SeriesChartType.Line; //FastLine series.ChartType = SeriesChartType.FastLine; series.IsXValueIndexed = true; // 自动设置索引 series.XValueType = ChartValueType.Time; // X轴为时间类型 // 数据点标记设置 series.MarkerStyle = MarkerStyle.Circle; // 圆形标记 series.MarkerColor = Color.Black; // 标记颜色 //设置点的大小 series.MarkerSize = 5; //设置曲线的颜色 series.Color = serierscolor; //设置曲线宽度 series.BorderWidth = 2; // 线宽 series.CustomProperties = "PointWidth=2"; // 点宽 series.IsValueShownAsLabel = true; // 显示数值标签 Chart_.Series.Add(series); // 添加到图表 //Debug.WriteLine("AddSerie"); } private void CreateChart() { Chart_.ChartAreas.Clear(); //chart = new Chart(); //this.panel1.Controls.Add(chart); // Chart_.Dock = DockStyle.Fill; // 填充到整个面板 Chart_.Visible = true; ChartArea chartArea = new ChartArea() { CursorX = { IsUserEnabled = true , IsUserSelectionEnabled = true ,SelectionColor = Color.SkyBlue, IntervalType = DateTimeIntervalType.Auto }, CursorY = { IsUserEnabled = true , IsUserSelectionEnabled = true ,SelectionColor = Color.SkyBlue, AutoScroll = true, }, AxisX = { ScaleView = {Zoomable=false ,MinSizeType = DateTimeIntervalType.Seconds}, LabelStyle = { Format = "HH:mm:ss.ff", Angle = -90 ,IsEndLabelVisible = true}, ScrollBar = { ButtonStyle = ScrollBarButtonStyles.All }, // 设置主网格线(透明度50%)Interval=0 自动 MajorGrid = { Enabled = true, LineColor = Color.FromArgb(50, Color.LightGray) ,Interval=0}, // 设置次网格线(更浅的透明度30%) MinorGrid = {Enabled = true, LineColor = Color.FromArgb(30, Color.LightGray), LineDashStyle=ChartDashStyle.Dash }, Title = @"Time",IsLabelAutoFit = true, LabelAutoFitMinFontSize = 5, Interval = 10, IntervalAutoMode = IntervalAutoMode.FixedCount, IntervalType = DateTimeIntervalType.NotSet, TextOrientation = TextOrientation.Auto, LineWidth = 2,LineColor = Color.Black, Enabled = AxisEnabled.True,Crossing = 0, //IsAuto }, AxisY ={ ScaleView = {Zoomable=false }, // 设置主网格线(透明度50%) MajorGrid = { Enabled = true , LineColor = Color.FromArgb(50, Color.LightGray), Interval=0}, // 设置次网格线(更浅的透明度30%) MinorGrid = {Enabled = true, LineColor = Color.FromArgb(30, Color.LightGray), LineDashStyle=ChartDashStyle.Dash }, Title = @"Value", LineWidth = 2, LineColor = Color.Black, Enabled = AxisEnabled.True }, Position = { Height = 85,Width = 95, X = 0,Y = 20 }, BackSecondaryColor = Color.White, //渐变背景色 BackGradientStyle = GradientStyle.TopBottom, //渐变方式 BackHatchStyle = ChartHatchStyle.None, //背景阴影 BorderDashStyle = ChartDashStyle.NotSet, //边框线样式 BorderWidth = 1, //边框宽度 BorderColor = Color.Black, }; Chart_.ChartAreas.Add(chartArea); Chart_.BackGradientStyle = GradientStyle.TopBottom; //图表的边框颜色、 Chart_.BorderlineColor = Color.FromArgb(26, 59, 105); //图表的边框线条样式 Chart_.BorderlineDashStyle = ChartDashStyle.Solid; //图表边框线条的宽度 Chart_.BorderlineWidth = 2; //图表边框的皮肤 Chart_.BorderSkin.SkinStyle = BorderSkinStyle.Emboss; Chart_.Paint += (s, e) => ValidateChartState(); //Debug.WriteLine("CreateChart"); } // 4. 添加图表状态验证方法 private void ValidateChartState() { if (!_isViewValid) // || !_isDataLoaded { //Debug.WriteLine("检测到无效视图状态,重新初始化图表..."); this.RefreshChart(); } } // 6. 增强RefreshChart方法 public void RefreshChart() { if (!_isDataLoaded) return; try { Chart_.SuspendLayout(); var series = Chart_.Series[0]; var points = series.Points; // 保存当前视图状态 var area = Chart_.ChartAreas[0]; double viewMin = area.AxisX.ScaleView.ViewMinimum; double viewMax = area.AxisX.ScaleView.ViewMaximum; bool isZoomed = !double.IsNaN(viewMin) && !double.IsNaN(viewMax); // 清除并重新添加数据 series.Points.Clear(); foreach (var (x, y) in xDB.Zip(yDB, (dt, val) => (dt, val))) { series.Points.AddXY(x, y); } // 恢复视图状态 if (isZoomed) { area.AxisX.ScaleView.Zoom(viewMin, viewMax); } else { area.AxisX.ScaleView.ZoomReset(); } _isViewValid = true; } finally { Chart_.ResumeLayout(); Chart_.Refresh(); } } public void PlayNextPoint(int pointsep = 10) { // 前置检查 if (Chart_.Series.Count <= 0 || xDB.Count != yDB.Count || _index >= xDB.Count) return; // 添加有效性检查 //if (!_isViewValid) //{ // RefreshChart(); // return; //} // 获取当前系列 Series series = Chart_.Series[0]; // 添加当前点(按间隔筛选) if (_index % pointsep == 0) { DateTime nowTime = xDB[_index]; double value = yDB[_index]; series.Points.AddXY(nowTime, value); // 视图滚动处理 UpdateViewForCurrentMode(pointsep = 10); } // 移动到下一个点 _index++; // 重置检查(放在最后确保完成当前点处理) if (_index >= xDB.Count) { _index = 0; } // Debug.WriteLine("CreateChart"); } private void UpdateViewForCurrentMode(int pointsep =10) { var area = Chart_.ChartAreas[0]; var axisX = area.AxisX; var series = Chart_.Series[0]; if (ShohType == "OverView") { //// 固定左侧为最早时间点 //DateTime minTime = xDB[0]; //axisX.Minimum = minTime.ToOADate(); //// 扩展右侧到最新时间点 //DateTime maxTime = xDB[_index]; //axisX.Maximum = maxTime.ToOADate(); //// 强制缩放以显示完整范围 //axisX.ScaleView.Zoom(axisX.Minimum, axisX.Maximum); const int viewSize = 250; int viewPoinr = _index / pointsep; Chart_.ChartAreas[0].AxisX.ScaleView.Position = 1; if (viewPoinr > viewSize) { double max = Chart_.ChartAreas[0].AxisX.Maximum; max = (viewPoinr / viewSize + 1) * viewSize; Chart_.ChartAreas[0].AxisX.Interval = max / viewSize; Chart_.ChartAreas[0].AxisX.ScaleView.Size = viewPoinr * 1.1; } else { Chart_.ChartAreas[0].AxisX.ScaleView.Size = viewSize; } //axisX.ScaleView.Position = 0; //axisX.IntervalAutoMode = IntervalAutoMode.VariableCount; //if (series.Points.Count > 10) //{ // axisX.Interval = series.Points.Count / 10.0; //} } else if (ShohType == "Follow") { const int viewSize = 50; axisX.Interval = 1; axisX.ScaleView.Size = viewSize; // 计算滚动位置(确保显示最新点) if (series.Points.Count > viewSize) { axisX.ScaleView.Position = series.Points.Count - viewSize; } else { axisX.ScaleView.Position = 0; } } } public void ResetPlayback() { _index = 0; if (Chart_.Series.Count > 0) { Chart_.Series[0].Points.Clear(); } // 修复:重置视图范围 AdjustView(); //Debug.WriteLine("ResetPlayback"); } private void AdjustView0() { if (xDB.Count < 2) return; var area = Chart_.ChartAreas[0]; DateTime minTime = xDB[0]; DateTime maxTime = xDB[xDB.Count -1]; area.AxisX.Minimum = startTime.ToOADate(); area.AxisX.Maximum = endTime.ToOADate(); // 使用索引器获取最后一个元素 area.AxisX.ScaleView.ZoomReset(); } public void TogglePlay() { // 修复1:如果已经播放完毕,重置索引 if (_index >= xDB.Count) { ResetPlayback(); } _isPlaying = !_isPlaying; PlayTimer.Enabled = _isPlaying; // 调试输出 //Debug.WriteLine($"TogglePlay 播放状态: {_isPlaying}, 当前索引: {_index}, 数据总数: {xDB.Count}"); } // 鼠标按下事件:开始拖动 private void Chart_MouseDown(object sender, MouseEventArgs e) { _isViewValid = true; // 标记视图有效 if (e.Button == MouseButtons.Left) { var chartArea = Chart_.ChartAreas[0]; _dragStartPoint = e.Location; _startPosition = chartArea.AxisX.ScaleView.Position; _startSize = chartArea.AxisX.ScaleView.Size; _isDragging = true; Chart_.Cursor = Cursors.SizeWE; // 设置水平拖动光标 } UpdateCoordinateLabels(e.Location); //Debug.WriteLine($"Chart_MouseDown"); } // 鼠标移动事件:处理拖动 private void Chart_MouseMove(object sender, MouseEventArgs e) { _isViewValid = true; // 标记视图有效 if (!_isDragging) return; var chartArea = Chart_.ChartAreas[0]; double positionChange = (e.X - _dragStartPoint.X) * chartArea.AxisX.ScaleView.Size / Chart_.Width; double newPosition = _startPosition - positionChange; // 保护边界 if (newPosition < chartArea.AxisX.Minimum) newPosition = chartArea.AxisX.Minimum; double maxPosition = chartArea.AxisX.Maximum - chartArea.AxisX.ScaleView.Size; if (newPosition > maxPosition) newPosition = maxPosition; chartArea.AxisX.ScaleView.Position = newPosition; //Debug.WriteLine($"Chart_MouseMove"); } // 鼠标释放事件:结束拖动 private void Chart_MouseUp(object sender, MouseEventArgs e) { _isViewValid = true; // 标记视图有效 if (e.Button == MouseButtons.Left && _isDragging) { _isDragging = false; Chart_.Cursor = Cursors.Default; } //Debug.WriteLine($"Chart_MouseUpe"); } // 鼠标滚轮事件:缩放功能 private void Chart_MouseWheel2(object sender, MouseEventArgs e) { _isViewValid = true; // 标记视图有效 var chartArea = Chart_.ChartAreas[0]; // 确保轴范围已初始化 if (double.IsNaN(chartArea.AxisX.Minimum) || double.IsNaN(chartArea.AxisX.Maximum) || xDB.Count == 0) { return; // 避免在未初始化状态下操作 } try { // 获取当前视图范围(OLE自动化日期格式) double currentPosition = chartArea.AxisX.ScaleView.Position; double currentSize = chartArea.AxisX.ScaleView.Size; // 计算鼠标在X轴上的比例位置 double mousePositionRatio = (double)e.X / Chart_.Width; // 将鼠标位置转换为轴上的实际值 double axisPosition = chartArea.AxisX.Minimum + mousePositionRatio * (chartArea.AxisX.Maximum - chartArea.AxisX.Minimum); // 缩放因子 double zoomFactor = e.Delta > 0 ? 0.9 : 1.1; // 计算新的大小(确保在合理范围内) double newSize = Math.Max(0.001, Math.Min( chartArea.AxisX.Maximum - chartArea.AxisX.Minimum, currentSize * zoomFactor )); // 计算新位置(确保在数据范围内) double newPosition = Math.Max( chartArea.AxisX.Minimum, Math.Min( chartArea.AxisX.Maximum - newSize, axisPosition - (mousePositionRatio * newSize) ) ); // 应用新的视图(使用安全的日期范围) chartArea.AxisX.ScaleView.Zoom( newPosition, newPosition + newSize ); } catch (ArgumentException ex) { Debug.WriteLine($"缩放错误: {ex.Message}"); // 恢复安全视图 ResetViewToSafeRange(); } //Debug.WriteLine($"Chart_MouseWheel2"); } private void Chart_MouseWheel(object sender, MouseEventArgs e) { _isViewValid = true; // 标记视图有效 var chartArea = Chart_.ChartAreas[0]; // 0. 初始化检查:确保有数据和有效的轴范围 if (xDB.Count == 0) return; // 1. 确保轴范围已初始化(处理未初始化情况) if (double.IsNaN(chartArea.AxisX.Minimum) || double.IsNaN(chartArea.AxisX.Maximum)) { // 初始化范围为完整数据集 chartArea.AxisX.Minimum = xDB[0].ToOADate(); chartArea.AxisX.Maximum = xDB[xDB.Count-1].ToOADate(); // C# 8.0索引语法 } // 2. 可靠获取当前视图大小(三种备选方案) double currentSize; // 方案A:直接获取ScaleView.Size if (!double.IsNaN(chartArea.AxisX.ScaleView.Size) && chartArea.AxisX.ScaleView.Size > 0) { currentSize = chartArea.AxisX.ScaleView.Size; } // 方案B:计算视图大小(适用于ScaleView.Size为NaN的情况) else if (!double.IsNaN(chartArea.AxisX.ScaleView.ViewMinimum) && !double.IsNaN(chartArea.AxisX.ScaleView.ViewMaximum)) { currentSize = chartArea.AxisX.ScaleView.ViewMaximum - chartArea.AxisX.ScaleView.ViewMinimum; } // 方案C:使用完整数据范围(最后备选) else { currentSize = chartArea.AxisX.Maximum - chartArea.AxisX.Minimum; } // 3. 计算鼠标位置对应的实际值 double mousePositionRatio = (double)e.X / Chart_.Width; double axisMousePosition = chartArea.AxisX.Minimum + mousePositionRatio * (chartArea.AxisX.Maximum - chartArea.AxisX.Minimum); // 4. 计算缩放因子 double zoomFactor = e.Delta > 0 ? 0.9 : 1.1; // 滚轮向上=放大(0.9),向下=缩小(1.1) // 5. 计算新视图大小(添加边界保护) double minAllowedSize = (chartArea.AxisX.Maximum - chartArea.AxisX.Minimum) * 0.001; // 最小显示0.1%范围 double newSize = Math.Max(minAllowedSize, currentSize * zoomFactor); newSize = Math.Min(newSize, chartArea.AxisX.Maximum - chartArea.AxisX.Minimum); // 6. 计算新视图位置(保持鼠标点位置不变) double newPosition = axisMousePosition - (mousePositionRatio * newSize); // 7. 应用边界约束 newPosition = Math.Max(chartArea.AxisX.Minimum, newPosition); newPosition = Math.Min(chartArea.AxisX.Maximum - newSize, newPosition); // 8. 应用缩放 try { chartArea.AxisX.ScaleView.Zoom(newPosition, newPosition + newSize); } catch (ArgumentException ex) { //Debug.WriteLine($"缩放错误: {ex.Message}"); // 恢复安全范围 ResetViewToSafeRange(); } //AdjustView2(); //ResetViewToSafeRange(); //AdjustView2(true); // AdjustView(); //ResetViewToSafeRange(); // SafeResetView(); //Chart_.ChartAreas[0].AxisX.ScaleView.Size = 250; // ResetPlayback(); // 更高效的方式是比较double值,然后设置轴的范围也是double(OLE日期) //double minOle = Chart_.Series[0].Points.Min(point => point.XValue); //double maxOle = Chart_.Series[0].Points.Max(point => point.XValue); //// 设置X轴的范围为整个数据范围 //Chart_.ChartAreas[0].AxisX.Minimum = minOle; //Chart_.ChartAreas[0].AxisX.Maximum = maxOle; //var area = Chart_.ChartAreas[0]; //area.AxisX.ScaleView.ZoomReset(); //area.AxisY.ScaleView.ZoomReset(); //Chart_.Refresh(); //Debug.WriteLine($"Chart_MouseWheel1 {Chart_.Series[0].Points.Count} s {Chart_.Series[0].Points.Max(point => point.XValue)} o"); //Debug.WriteLine($"Chart_MouseWheel1 {Chart_.ChartAreas.Count} {Chart_.Series.Count}"); } // 添加安全范围重置方法 private void ResetViewToSafeRange() { if (xDB.Count == 0) return; var area = Chart_.ChartAreas[0]; DateTime minDate = xDB.Min(); DateTime maxDate = xDB.Max(); area.AxisX.Minimum = minDate.ToOADate(); area.AxisX.Maximum = maxDate.ToOADate(); area.AxisX.ScaleView.ZoomReset(); //Debug.WriteLine($"ResetViewToSafeRange"); } // 修改 AdjustView 方法(确保初始化范围) private void AdjustView(bool fullView = false) { if (xDB.Count < 2) return; var area = Chart_.ChartAreas[0]; // 3. 设置轴范围(使用OLE日期值) double minDate = xDB[0].ToOADate(); double maxDate = xDB[xDB.Count - 1].ToOADate(); // 使用最后一个元素 // 4. 设置前清除缩放状态(关键步骤) //area.AxisX.ScaleView.ZoomReset(); // 5. 设置最小最大值 area.AxisX.Minimum = minDate; area.AxisX.Maximum = maxDate; // 7. 强制刷新 Chart_.Refresh(); // 如果是完整视图模式,重置缩放 if (fullView) { area.AxisX.ScaleView.ZoomReset(); ShohType = "OverView"; } //Debug.WriteLine($"AdjustView"); } // 缩放时动态调整网格线 private void OnAxisViewChanged(object sender, ViewEventArgs e) { // 当视图改变时确保范围安全 //var axis = e.Axis; //if (axis.AxisName == AxisName.X) //{ // SetSafeXRange( // DateTime.FromOADate(e.NewPositionStart), // DateTime.FromOADate(e.NewPositionEnd) // ); //} if (e.Axis.AxisName == AxisName.X || e.Axis.AxisName == AxisName.Y) { //UpdateGridDensity(); } } // 根据缩放级别动态更新网格密度 private void UpdateGridDensity() { var area = Chart_.ChartAreas[0]; var axisX = area.AxisX; var axisY = area.AxisY; // 计算X轴网格密度(基于可见范围) double xRange = axisX.ScaleView.ViewMaximum - axisX.ScaleView.ViewMinimum; double xInterval = CalculateOptimalInterval(xRange); // 计算Y轴网格密度 double yRange = axisY.ScaleView.ViewMaximum - axisY.ScaleView.ViewMinimum; double yInterval = CalculateOptimalInterval(yRange); // 应用网格间隔 axisX.MajorGrid.Interval = xInterval; axisX.MinorGrid.Interval = xInterval / 5; // 次要网格更密集 axisY.MajorGrid.Interval = yInterval; axisY.MinorGrid.Interval = yInterval / 5; // 更新标签间隔(防止标签重叠) axisX.LabelStyle.Interval = xInterval * 2; axisY.LabelStyle.Interval = yInterval * 2; //Debug.WriteLine($"UpdateGridDensity"); } // 计算最优网格间隔(基于对数缩放) private double CalculateOptimalInterval1(double range) { if (range <= 0) return 1; // 计算数量级(10的幂) int magnitude = (int)Math.Floor(Math.Log10(range)); double baseInterval = Math.Pow(10, magnitude); // 确定最佳间隔(1, 2, 5序列) if (range / baseInterval < 2) return baseInterval / 5; else if (range / baseInterval < 5) return baseInterval / 2; else if (range / baseInterval < 10) return baseInterval; else if (range / baseInterval < 20) return baseInterval * 2; else return baseInterval * 5; } // 批量加载数据点 (替代原来的逐点添加) public void LoadAllData() { try { _isDataLoaded = true; _isViewValid = true; this._index = 0; Chart_.SuspendLayout(); Chart_.Series[0].Points.SuspendUpdates(); InitChart(); for (int i = 0; i < xDB.Count; i++) { // 批量添加点(每100点刷新一次) if (i % 100 == 0 || i == xDB.Count - 1) { Chart_.Series[0].Points.AddXY(xDB[i], yDB[i]); //Chart_.Refresh(); //Application.DoEvents(); // 允许UI处理事件 } //if (i % 100 == 0) //{ //} } //AdjustView(fullView: true); this.RefreshChart(); _isDataLoaded = true; _isViewValid = true; } finally { Chart_.Series[0].Points.ResumeUpdates(); Chart_.ResumeLayout(); Chart_.Refresh(); } //InitChart(); //for (int i = _index; i < xDB.Count; i++) //{ // PlayNextPoint(); //} //AdjustView(); //Debug.WriteLine($"LoadAllData"); return; //if (xDB.Count == 0) return; //Chart_.Series[0].Points.SuspendUpdates(); //Chart_.Series[0].Points.Clear(); //for (int i = 0; i < xDB.Count; i++) //{ // Chart_.Series[0].Points.AddXY(xDB[i], yDB[i]); //} //AdjustView(); //Chart_.Series[0].Points.ResumeUpdates(); //return; if (Chart_.Series.Count == 0 || xDB.Count == 0) return; Series series = Chart_.Series[0]; series.Points.Clear(); // 使用DataBindXY批量绑定数据 series.Points.DataBindXY( xDB.Select(dt => dt.ToString("HH:mm:ss.ffff")).ToArray(), yDB ); AdjustView(); //AdjustView(fullView: true); _index = xDB.Count; // 更新索引到末尾 } // 添加更新坐标标签的方法 private void UpdateCoordinateLabels(Point mousePos) { try { var chartArea = Chart_.ChartAreas[0]; // 将鼠标位置转换为坐标值 double xValue = chartArea.AxisX.PixelPositionToValue(mousePos.X); double yValue = chartArea.AxisY.PixelPositionToValue(mousePos.Y); // 修复时间显示问题:只提取时间部分 DateTime baseDate = new DateTime(1899, 12, 30); // OLE自动化日期基准 DateTime fullDateTime = baseDate.AddDays(xValue); TimeSpan timePart = fullDateTime.TimeOfDay; // 格式化时间(毫秒保留三位) string timeString = $"{timePart.Hours:D2}:{timePart.Minutes:D2}:{timePart.Seconds:D2}.{timePart.Milliseconds:D3}"; _lblXCoord.Text = $"X: {timeString}"; _lblYCoord.Text = $"Y: {Math.Round(yValue, 3)}"; } catch { _lblXCoord.Text = "X: --"; _lblYCoord.Text = "Y: --"; } } // 在图表调整大小时保持标签位置 private void Chart_Resize(object sender, EventArgs e) { // 保持标签在左上角固定位置 _lblXCoord.Location = new Point(10, 10); _lblYCoord.Location = new Point(10, 35); } // 修改现有的AdjustView方法 // 修复视图调整方法 private void AdjustView2(bool fullView = false) { if (xDB.Count == 0) return; var area = Chart_.ChartAreas[0]; double minX = xDB[0].ToOADate(); double maxX = xDB.Last().ToOADate(); // 设置X轴范围 area.AxisX.Minimum = minX; area.AxisX.Maximum = maxX; if (fullView) { area.AxisX.ScaleView.ZoomReset(); ShohType = "OverView"; } else if (ShohType == "Follow") { double viewSize = area.AxisX.ScaleView.Size; if (double.IsNaN(viewSize) || viewSize <= 0) viewSize = (maxX - minX) * 0.1; // 默认显示10%范围 double newPosition = Math.Max(minX, maxX - viewSize); area.AxisX.ScaleView.Position = newPosition; } // 自动调整Y轴范围 double minY = yDB.Min(); double maxY = yDB.Max(); double margin = (maxY - minY) * 0.1; // 10%边距 area.AxisY.Minimum = minY - margin; area.AxisY.Maximum = maxY + margin; } // 修复网格密度计算方法 private double CalculateOptimalInterval(double range) { if (range <= 0) return 1; double logVal = Math.Log10(range); int magnitude = (int)Math.Floor(logVal); double fraction = logVal - magnitude; double[] intervals = { 1, 2, 5, 10 }; double baseInterval = Math.Pow(10, magnitude); // 选择最合适的间隔 if (fraction < 0.3) return baseInterval * intervals[0]; if (fraction < 0.6) return baseInterval * intervals[1]; return baseInterval * intervals[2]; } // 8. 添加安全缩放重置方法 public void SafeResetView() { var area = Chart_.ChartAreas[0]; // 禁用自动范围 //area.AxisX.IsAutoMaximum = false; //area.AxisX.IsAutoMinimum = false; // 重置缩放视图 try { area.AxisX.ScaleView.ZoomReset(); } catch { // 故障恢复 if (xDB.Count > 0) { double min = xDB[0].ToOADate(); double max = xDB[xDB.Count - 1].ToOADate(); // 设置最小最大值 area.AxisX.Minimum = min; area.AxisX.Maximum = max; // 强制设置视图 area.AxisX.ScaleView.Zoom(min, max); } } _isViewValid = true; } } 问题没有修复 x下标是10:03:29.97 上面显示为 23:38.44.760
11-13
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值