photoshop中比较常用的一个功能就是曲线调整,如图
通过鼠标添加、删除、拖动曲线节点,这样即可调整图像参数。这个功能就其思路来说(这里只考虑曲线本身,数据存储等不在此列),是比较简单的:
曲线由一组point表示节点
鼠标移动节点实际是修改单个point
插入删除point
一个节点是一个手柄handle,就是一个小方块
在paint里画出一条经过所有节点的曲线drawcurve
随便画个十字准星表示当前节点
鼠标按下,判断是否在某个已有节点里,如果有,标记之,否则添加新节点
鼠标按下且移动,如果已有节点,则节点坐标为鼠标坐标
刷新画图
完成后的程序操作演示(动画):
下面是部分示例代码:
节点:
list44a45ae2deb400dab67a6f07325591bb points;
绘制节点手柄:
rectangle gethandle(point p)
{
    rectangle rect = new rectangle(
        p.x - 3,
        p.y - 3,
        6,
        6);
    return rect;
}
判断某点是否位于手柄区域:
bool ishandle(point p)
{
    foreach (point pt in points)
    {
        if (isinside(p, gethandle(pt)))
        {
            downindex = points.indexof(pt);
            downpoint = pt;
            current = pt;
            return true;
        }
    }
    return false;
}
注意这个部分可以适当放大一下判断区域,这样便于鼠标操作(手柄太小,不易点击)。
绘制手柄:
void drawhandle(graphics g, point p)
{
    if (points.indexof(p) == downindex)
        g.fillrectangle(
            brushes.black,
            gethandle(p));
    else
        g.drawrectangle(
            pens.black,
            gethandle(p));
}
绘制曲线:
void drawcurve(graphics g)
 {
     g.drawcurve(pens.black, points.toarray());
 }
曲线绘制采用了graphics类的基数样条绘制方法,默认张力0.5。
绘制十字定位线(辅助功能):
void drawcrosshair(graphics g, point p)
{
    g.drawline(
        pens.gray,
        0, p.y,
        clientrect.width,
        p.y);
    g.drawline(
        pens.gray,
        p.x,
        0,
        p.x,
        clientrect.height);
}
鼠标拖动:
protected override void onmousemove(mouseeventargs e)
{
    mousepoint = e.location;
    if (mousedown)
    {
        if (current != null)
        {
            current = mousepoint;
        }
        refresh();
    }
}
更多带节点曲线,鼠标可拖动节点调整曲线,类似photoshop。
   
 
   