鼠标绘图的原理

  我们每个人都使用过Window的画图软件,我家在我五年级的时候购买了第一台电脑,系统是xp,那时我除了每天逛4399玩点造梦西游、赛尔号、洛克王国之类的游戏以外,偶尔也会想通过自己的双手创造些什么,于是就会鼓捣起电脑自带的画图软件,拖几个矩形、拉几条直线,然后用填充油桶涂上各种各样的颜色,宛如一张抽象画作,我便会沉浸在画中各种各样不规则的结构上,仿佛在欣赏画作的美感。

  言归正传,鼠标作为电脑的输入设备,承载着非常重要的作用,它使得电脑的使用变得简单,用户只要用鼠标就能完成一系列任务,而不是使用需要一定抽象思维的代码来让电脑完成任务,比如我们做物理实验时,需要用最小二乘法来拟合记录的一系列数据,我们要么使用最小二乘法公式,计算数据的平均值,然后求和公式,得到最后拟合的参数,或者我们使用Matlab其中的polyfit函数,直接拟合出直线或曲线出来,但对于我们一般网友来说,我更倾向于找一个最小二乘法在线计算的网站,使用鼠标和键盘就能轻松得到结果。所以这就是图形界面的好处,用户只需要对输入输出设备就能完成各种任务,而不需要考虑系统的底层逻辑。

  在画图软件中,使用鼠标完成绘图操作被具象化为一支铅笔,跟现实生活中使用笔来绘图相对应,下笔,移动笔,收笔,就完成了一个笔画或是一个线段的绘制,鼠标绘图也是这种模式,按下鼠标左键,移动鼠标,松开左键,就完成了一笔的绘制。我们新建一个txt文件,将后缀改为png的图像格式,并右键以编辑方式打开, 将画布拉大,选择铅笔,画上几笔。

 

 

  如果你鼠标移动地像我一样快,就能注意到下面这个细节:这不是一条一条的直线吗?弯折还是可以看见的。

 

   所以我们可以想象鼠标的绘图原理,我们每时每刻都在记录鼠标的坐标信息,当鼠标按下左键时,我们保存鼠标在该时刻的坐标记作P1,鼠标一直在拖动,我们保存下一时刻的鼠标坐标记作P2,将P1、P2分别作为线段的起点和终点连线,打印在显示器上,鼠标在拖动,保存下一时刻的鼠标坐标记作P3,连接P2、P3......等到鼠标左键抬起时,就完成了最后一个线段的绘制,于是一整段鼠标绘制的线就显示出来了,这也就是鼠标绘图的整个过程,当然我们不必用一个二维数组来一直保存每一个时刻的鼠标坐标信息,我们只要声明两个坐标,分别表示线段的起点和终点,在鼠标拖动过程中不断改变两个坐标的值就可以完成整个过程,比如当我用起点和终点绘制完一个线段后,将终点设置为下一个线段的起点,再接收一个鼠标坐标作为下一个线段的终点,这样,下一个线段也就绘制出来了。

  代码逻辑上的描述如下:

while(true) {
    msg = getmouse();            // 获取当前时刻鼠标信息 
    
    if(msg.is_left_down())       // 如果鼠标左键按下 
        to_draw = 1;             // 则进行绘图 
    else
        to_draw = 0;
    
    start_point = end_point;     // 将终止点作为起始点 
    end_point = (msg.x, msg.y);  // 将当前坐标点作为终止点 
    
    if(to_draw)
        line(start_point, end_point);  // 根据前后坐标绘制直线 
}

  每过一个时刻就会运行一次大括号中间的操作,于是,鼠标绘图就这样实现了,下面再附上一段C语言加EGE图像库的代码,如果配置了EGE库,是可以直接运行的:

#include "graphics.h"

int main() {
    initgraph(1000, 600, 0);
    setcolor(GREEN);
    ege_enable_aa(true);
    int pre_x, pre_y, now_x, now_y;
    int toDraw = 0;
    
    for (; is_run();) {
        mouse_msg msg = {0};
        msg = getmouse();
        
        if(msg.is_left()) {
            if(msg.is_down()) {
                toDraw = 1;
            }
            else {
                toDraw = 0;
            }
        }
        pre_x = now_x;
        pre_y = now_y;
        now_x = msg.x;
        now_y = msg.y;
        
        if(msg.x>=0&&msg.x<=1000 && msg.y>=0&&msg.y<=600) {
            xyprintf(1,1,"[%d,%d]",msg.x, msg.y);
        }
        if(toDraw) {
            line(pre_x, pre_y, now_x, now_y);
        }
    }
    
    getch();
    closegraph();
    return 0;
}
View Code

  运行结果如下:

 

posted @ 2021-06-02 18:04  HanselHuang  阅读(74)  评论(0编辑  收藏  举报