如何在雷达图中按指定公里数绘制圆形与可变范围锥形体?
实现指定公里数的雷达同心圆绘制与锥形体范围动态调整
一、计算并绘制指定公里数的同心圆
首先明确比例尺:当前512x512画布对应300公里范围(红色外圆),因此像素与公里的换算比例为:目标范围像素直径 = (目标公里数 / 300) * 512,以此为基础计算同心圆的尺寸。
实现步骤
- 定义全局基准参数,方便后续复用:
private const int BASE_CANVAS_SIZE = 512; // 画布固定尺寸 private const int BASE_RANGE_KM = 300; // 基准公里数(对应最大外圆)
- 编写通用方法,根据输入的公里数生成对应椭圆的矩形区域(以画布中心为圆心):
private RectangleF GetRangeRect(float targetKm) { // 计算目标范围相对于基准的缩放比例 float scale = targetKm / BASE_RANGE_KM; float diameter = BASE_CANVAS_SIZE * scale; // 计算矩形左上角坐标,确保圆心与画布中心重合 float offset = (BASE_CANVAS_SIZE - diameter) / 2; return new RectangleF(offset, offset, diameter, diameter); }
- 在
Paint事件中调用方法绘制多组同心圆:
private void pictureBox1_Paint(object sender, PaintEventArgs e) { e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; // 绘制300公里基准外圆 e.Graphics.DrawEllipse(new Pen(Color.Red, 2f), GetRangeRect(300)); // 绘制200公里圆 e.Graphics.DrawEllipse(new Pen(Color.Blue, 1.5f), GetRangeRect(200)); // 绘制100公里圆 e.Graphics.DrawEllipse(new Pen(Color.Green, 1f), GetRangeRect(100)); // 后续保留原有锥形体绘制逻辑 }
二、通过文本框动态调整新增锥形体的范围
实现步骤
- 界面添加控件:新增
TextBox(命名txtConeRange)用于输入公里数,新增Button(命名btnUpdateCone)触发范围更新(也可直接监听TextBox的TextChanged事件)。 - 定义全局变量存储自定义锥形体的目标公里数:
private float customConeRangeKm = 100; // 默认初始值
- 文本框输入校验与更新逻辑(按钮点击事件):
private void btnUpdateCone_Click(object sender, EventArgs e) { if (float.TryParse(txtConeRange.Text, out float inputKm) && inputKm > 0 && inputKm <= BASE_RANGE_KM) { customConeRangeKm = inputKm; pictureBox1.Invalidate(); // 触发画布重绘 } else { MessageBox.Show("请输入0-300之间的有效数字"); } }
- 修改
Paint事件,保留原有锥形体,新增绘制自定义范围的锥形体:
private void pictureBox1_Paint(object sender, PaintEventArgs e) { e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; var center = new PointF(BASE_CANVAS_SIZE / 2f, BASE_CANVAS_SIZE / 2f); // --- 绘制同心圆部分(保留上述代码)--- e.Graphics.DrawEllipse(new Pen(Color.Red, 2f), GetRangeRect(300)); e.Graphics.DrawEllipse(new Pen(Color.Blue, 1.5f), GetRangeRect(200)); e.Graphics.DrawEllipse(new Pen(Color.Green, 1f), GetRangeRect(100)); // --- 原有锥形体绘制(保留原逻辑)--- RectangleF outerRect = GetRangeRect(BASE_RANGE_KM); outerRect.Inflate(-(radarThickness / 2.0f), -(radarThickness / 2.0f)); var pathOuter = new GraphicsPath(); var pathOriginalCone = new GraphicsPath(); pathOuter.AddEllipse(outerRect); pathOriginalCone.StartFigure(); pathOriginalCone.AddArc(outerRect, coneRotationAngle, coneSweepAngle); var originalArcPoints = pathOriginalCone.PathPoints; PointF originalFirst = originalArcPoints[0]; PointF originalLast = originalArcPoints[originalArcPoints.Length - 1]; pathOriginalCone.AddLines(new[] { center, originalLast, center, originalFirst }); pathOriginalCone.CloseFigure(); var outerPen = new Pen(Color.FromArgb(100, Color.Red), radarThickness); var originalConeBrush = new LinearGradientBrush(center, originalFirst, Color.FromArgb(200, Color.Orange), Color.FromArgb(20, Color.Orange)); e.Graphics.FillPath(originalConeBrush, pathOriginalCone); e.Graphics.DrawPath(outerPen, pathOuter); // --- 新增自定义范围的锥形体--- RectangleF customConeRect = GetRangeRect(customConeRangeKm); customConeRect.Inflate(-(radarThickness / 2.0f), -(radarThickness / 2.0f)); var pathCustomCone = new GraphicsPath(); pathCustomCone.StartFigure(); pathCustomCone.AddArc(customConeRect, coneRotationAngle, coneSweepAngle); var customArcPoints = pathCustomCone.PathPoints; PointF customFirst = customArcPoints[0]; PointF customLast = customArcPoints[customArcPoints.Length - 1]; pathCustomCone.AddLines(new[] { center, customLast, center, customFirst }); pathCustomCone.CloseFigure(); // 用青色区分新增锥形体,可自行调整颜色 var customConeBrush = new LinearGradientBrush(center, customFirst, Color.FromArgb(200, Color.Cyan), Color.FromArgb(20, Color.Cyan)); e.Graphics.FillPath(customConeBrush, pathCustomCone); // 释放GDI+资源,避免内存泄漏 outerPen.Dispose(); originalConeBrush.Dispose(); customConeBrush.Dispose(); pathOuter.Dispose(); pathOriginalCone.Dispose(); pathCustomCone.Dispose(); }
注意事项
- 确保
radarThickness、coneRotationAngle、coneSweepAngle这些变量已在类中定义并赋值。 - 所有GDI+对象(Pen、Brush、GraphicsPath)使用后必须调用
Dispose()释放资源,也可使用using语句包裹自动释放。
内容的提问来源于stack exchange,提问作者Daniel Lip
相关产品推荐
相关产品推荐

