• Windows控制台下绘制简单图形


      最近接触到一个很有意思的问题,如何在Windows控制台下画图,翻遍了C的头文件也没找到画图的函数,好吧,那就用Windows提供的API函数吧,看来想移植是没戏了。先画一个简单的图,类似心电图那种吧,假设得到的数据是纵坐标的值,横坐标默认从0开始,每隔512uS(微秒的那个符号不会打)得到一个纵坐标值,要求将所有纵坐标值连起来,就以这个简单的程序为例吧。

      既然有了需求,实现起来就简单了,首先我们应该有一个控制台窗口的上下文(device context)句柄,然后使用MoveToExLineTo函数连线就行了。代码如下:

      

    #include <windows.h>
    #include
    <stdio.h>
    #include
    <conio.h>
    #include
    "data.h"  //声明了名为point的二维数组,以及记录数组元素个数的NUMBER常量

    //
    //下列X-Y坐标平面的值取决于控制台的尺寸,需要根据实际情况进行调整
    //


    //起始X坐标
    #define X_START 10

    //结束X坐标
    #define X_END 650

    //每个值的X坐标增量,相当于512uS
    #define X_INC 10

    //Y坐标
    #define Y 250

    int main()
    {
    HWND hwnd;
    HDC hdc;
    int i;

    //获取console的设备上下文句柄
    hwnd = GetConsoleWindow();
    hdc
    = GetDC(hwnd);

    //调整一下console背景颜色,否则看不清线条
    system("color 3D");

    //起始位置,Windows中窗口的坐标系相当于直角坐标系第一象限翻转到第四象限
    MoveToEx(hdc,X_START,Y,NULL);

    //画基准坐标线
    LineTo(hdc,X_END,Y);

    //开始绘图
    MoveToEx(hdc,X_START,Y,NULL);
    for (i = 0; i < NUMBER; i++)
    {
    LineTo(hdc,point[i].x,point[i].y);
    }
    _getch();
    return 0;
    }

      但是这个程序存在一个问题,就是如果控制台被其它窗口遮住后,已经绘制的线条不会重绘,也就意味着那部分线条看不见了,只能重新运行程序,这个问题怎么解决呢?我也不知道,不过可以将整个函数包含一个while循环里,如果自己是顶层窗口就重新绘制,只是这样似乎代价太大了,呵呵。

      来看一下这个程序绘制的图形吧。

      line

      既然能绘制出线条自然就可以会绘制出柱形图之类的图形,稍微修改一下就可以了,代码就不贴了,效果如下图。

      photo

      上面这些都比较好画,那么如果画圆呢?

      我想到两种方法,第一种方法是计算,首先分别计算出最大和最小的X、Y值(xmin,xmax,ymin,ymax),然后根据X^2+Y^2=R^2,在for (x = xmin; x <= xmax; x++)内部计算Y值,最后画点就是了;这个应该是比较简单的。

      第二种方法是扫描,左上角(xmin,ymin)、右上角(xmax,ymin)、左下角(xmin,ymax)和右下角(xmax,ymax)这四个点确定一个正方形,对正方形内部对每个点进行运算,也是根据X^2+Y^2=R2,只是现在根据X和Y算出R0,然后跟R对比而已,而且比第一种方法多了一个判断——是否到达行末,若到达行末则跳到下一行,若已经到了最后一行的最后一列,那就跳出循环。不过这个方法显然比较奢侈,如果半径增大n倍的话,计算量增大了n^2倍。就贴这种方法的代码吧。

      

    void circle(POINT *center,int radius)
    {
    HWND hwnd;
    HDC hdc;
    int xmin = center->x - radius;
    int xmax = center->x + radius;
    int ymin = center->y - radius;
    int ymax = center->y + radius;
    POINT point;

    hwnd
    = GetConsoleWindow();
    hdc
    = GetDC(hwnd);

    point.x
    = xmin;
    point.y
    = ymin;
    MoveToEx(hdc,center
    ->x,center->y - radius,NULL);
    while (TRUE)
    {
    if (fabs(sqrt(pow2(point.x - center->x) + pow2(point.y - center->y)) - radius) <= 1)
    {
    DrawPoint(hdc,
    &point);
    }
    //是否到达行末
    if (point.x == xmax)
    {
    if (point.y == ymax)
    {
    break;
    }
    else
    {
    point.x
    = xmin;
    point.y
    ++;
    continue;
    }
    }
    point.x
    ++;
    }
    }

      绘制的圆如下图:

      circle

  • 相关阅读:
    java 获取文本一行一行读
    postman 测试api接口
    MariaDB 默认是禁止远程访问的 我们改掉它
    mysql 查询近三个月数据
    Springboot配置拦截器
    springboot 基于@Scheduled注解 实现定时任务
    springboot 配置访问本地图片
    springboot上传文件大小限制的配置
    vue中toggle切换的3种写法
    vue怎么给自定义组件绑定原生事件
  • 原文地址:https://www.cnblogs.com/pianoid/p/2060001.html
Copyright © 2020-2023  润新知