目录
一、曲线编辑器实现功能
二、实现方法说明
三、关键代码说明
1、绘制背景板和曲线
2、绘制坐标系面板
3、绘制曲线
四、工程下载连接
一、曲线编辑器实现功能
添加或者删除控制点,通过移动控制点来修改曲线形状
二、实现方法说明
1、坐标系系统:
使用0-500的范围映射到屏幕坐标系
自动绘制网格线(间隔50单位)
坐标轴显示在左侧和底部
2、控制点功能:
左键点击空白区域添加新控制点
拖动现有控制点调整位置
自动按X坐标排序保持曲线有效性
限制控制点移动范围(防止越界和重叠)
3、 曲线绘制:
使用GraphicsPath.AddCurve方法实现平滑曲线
张力系数设为0.5(可调整)
实时更新曲线显示
4、坐标转换:
MapXToScreen/MapYToScreen:将逻辑坐标转换为屏幕坐标
MapScreenToLogical:将屏幕坐标转换为逻辑坐标
5、交互优化:
双缓冲技术消除闪烁
抗锯齿处理
控制点吸附范围判断
二、使用说明:
点击空白区域添加新控制点
拖动红色控制点调整曲线形状
控制点自动按X坐标排序
曲线实时更新
三、扩展建议:
添加右键菜单删除控制点
实现曲线预设功能
添加数值输入框精确调整坐标
增加坐标轴标签
实现数据导出/导入功能
添加撤销/重做功能
*
该实现提供了基本的曲线编辑功能,可以作为图像处理工具的基础模块,后续可根据具体需求添加更多高级功能。
三、关键代码说明
1、绘制背景板和曲线
private void Form1_Paint(object sender, PaintEventArgs e)
{
//base.OnPaint(e);
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
// 绘制坐标系背景
DrawCoordinateSystem(g);
// 绘制控制点
foreach (var point in controlPoints)
{
DrawControlPoint(g, point);
}
// 绘制曲线
if (controlPoints.Count >= 2)
{
DrawCurve(g);
}
}
2、绘制坐标系面板
private void DrawCoordinateSystem(Graphics g)
{
// 绘制坐标系背景
g.FillRectangle(Brushes.White, coordinateArea);
// 绘制坐标轴
using (Pen axisPen = new Pen(Color.Black, 2))
{
// X轴
g.DrawLine(axisPen,
coordinateArea.Left,
coordinateArea.Bottom,
coordinateArea.Right,
coordinateArea.Bottom);
// Y轴
g.DrawLine(axisPen,
coordinateArea.Left,
coordinateArea.Bottom,
coordinateArea.Left,
coordinateArea.Top);
}
// 绘制网格线
using (Pen gridPen = new Pen(Color.LightGray, 1))
{
// X轴网格
for (float x = 0; x <= 500; x += 50)
{
float screenX = MapXToScreen(x);
g.DrawLine(gridPen, screenX, coordinateArea.Top, screenX, coordinateArea.Bottom);
}
// Y轴网格
for (float y = 0; y <= 500; y += 50)
{
float screenY = MapYToScreen(y);
g.DrawLine(gridPen, coordinateArea.Left, screenY, coordinateArea.Right, screenY);
}
}
}
3、绘制曲线
private void DrawCurve(Graphics g)
{
if (controlPoints.Count < 2) return;
List<PointF> screenPoints = new List<PointF>();
foreach (var point in controlPoints)
{
screenPoints.Add(new PointF(
MapXToScreen(point.X),
MapYToScreen(point.Y)));
}
// 使用GraphicsPath绘制平滑曲线
using (GraphicsPath path = new GraphicsPath())
using (Pen curvePen = new Pen(Color.Blue, 2))
{
path.AddCurve(screenPoints.ToArray(), 0.5f); // 张力系数
g.DrawPath(curvePen, path);
}
}
4、鼠标按下添加控制点和移动控制点
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
//base.OnMouseDown(e);
// 检查是否点击控制点
for (int i = 0; i < controlPoints.Count; i++)
{
PointF logicalPoint = controlPoints[i];
float screenX = MapXToScreen(logicalPoint.X);
float screenY = MapYToScreen(logicalPoint.Y);
if (Math.Abs(e.X - screenX) < pointRadius * 2 &&
Math.Abs(e.Y - screenY) < pointRadius * 2)
{
selectedPointIndex = i;
return;
}
}
// 添加新点(限制在坐标系区域内)
if (coordinateArea.Contains(e.Location))
{
PointF newPoint = MapScreenToLogical(e.Location);
controlPoints.Add(newPoint);
controlPoints.Sort((a, b) => a.X.CompareTo(b.X)); // 按X坐标排序
selectedPointIndex = controlPoints.IndexOf(newPoint);
this.Invalidate();
}
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
//base.OnMouseMove(e);
if (selectedPointIndex >= 0 && e.Button == MouseButtons.Left)
{
// 限制移动范围在坐标系内
float x = Math.Max(coordinateArea.Left, Math.Min(e.X, coordinateArea.Right));
float y = Math.Max(coordinateArea.Top, Math.Min(e.Y, coordinateArea.Bottom));
// 更新控制点位置
PointF newPoint = MapScreenToLogical(new Point((int)x, (int)y));
// 保持X坐标有序
if (selectedPointIndex > 0 && newPoint.X < controlPoints[selectedPointIndex - 1].X)
newPoint.X = controlPoints[selectedPointIndex - 1].X;
if (selectedPointIndex < controlPoints.Count - 1 && newPoint.X > controlPoints[selectedPointIndex + 1].X)
newPoint.X = controlPoints[selectedPointIndex + 1].X;
controlPoints[selectedPointIndex] = newPoint;
this.Invalidate();
}
}
四、工程下载连接
https://download.csdn.net/download/panjinliang066333/90519250