忘備録-備忘録

技術的な備忘録

サーマルカメラを使う

2020-07-10 19:49:25 | raspberry ...
サーマルカメラLepton3.5とUSB接続アダプタPureThermal 2 を手に入れたのでRaspberry Pi4で使ってみました。この組み合わせでRaspberry Pi4からは UVC(USB Video Class) として認識されます。

ファームウェアアップデート
現時点のファームウェアではRaspberry Pi4と正しくデータのやり取りができないため、ファームウェアをアップデートする必要があります。方法は"Raspberry Pi 4 VL805ファームウェアリリース0138a1"に書かれています。
最初にファームウェアをダウンロードします。
にアクセスしてvl805-000138a1.binファイルをダウンロードします。
次に示すようにアップデートを行い再起動後に確認を行います。
$ sudo rpi-eeprom-update -u vl805-000138a1.bin

----再起動-----

$ sudo rpi-eeprom-update
BCM2711 detected
Dedicated VL805 EEPROM detected
BOOTLOADER: up-to-date
CURRENT: 2020年  4月 16日 木曜日 17:11:26 UTC (1587057086)
 LATEST: 2020年  4月 16日 木曜日 17:11:26 UTC (1587057086)
 FW DIR: /lib/firmware/raspberrypi/bootloader/critical
VL805: up-to-date
CURRENT: 000138a1
 LATEST: 000137ad

動作確認
マニュアルにはguvcviewで画像が確認できると説明がありますが、うまく動作しません。VLCでは画像を確認できます。

プログラム
Raspberry PiのカメラをGUIで操作する2にあるプログラムで画像を表示させることができます。

参考

塗りつぶした多角形の描画

2020-05-26 21:49:29 | Linux
点を打つ関数pset()のみを使用して塗りつぶした多角形(ポリゴン)を描くプログラムを作成しました。基本となるアルゴリズム・プログラムは多角形の塗りつぶし1多角形の塗りつぶし2を使わせてもらいました。グラフィックにはEGGX / ProCALLを使用しています。プログラムの作成はRaspberry Pi4で行っています。 

ソースコード
#include <stdio.h>
#include <stdlib.h>
#include <eggx.h> /* EGGX を使う時に必要 */

/*
 * ポリゴンを構成する直線を表す構造体
 */
struct EDGBUF {
    double X;   /* 交点のX座標(初期値は始点のX座標) */
    int Y0;  /* 始点のY座標 */
    int Y1;  /* 終点のY座標 */
    double a;    /* 傾き(dX/dY) */
};

/************************** 
 * 頂点のリストより辺リストの作成する 
 * 引数 int dataN:頂点の数
 *      signed short int * ApexList;  頂点リスト
 *      struct EDGBUF * Edge;         辺リスト
 * 戻り値 辺リスト
 */
struct EDGBUF *GenerateEdgeList(int dataN,int *ApexList, struct EDGBUF *Edge )
{
    signed short int x,y;
    int i;

    for ( i = 0 ; i < dataN ; i++ ) {
        x = *( ApexList + 2 ) - *ApexList;
        ApexList++;
        y = *( ApexList + 2 ) - *ApexList;
        ApexList++;
        if ( y != 0 ) {
            Edge[i].X =  ( y > 0 ) ? * ( ApexList - 2 ) : *ApexList;
            Edge[i].Y0 = ( y > 0 ) ? * ( ApexList - 1 ) : * ( ApexList + 1);
            Edge[i].Y1 = ( y > 0 ) ? * ( ApexList + 1 ) : * ( ApexList - 1);
            Edge[i].a = (double) x /(double) y;
        }
    }
    return(Edge);
}

/***************************** 
 * X座標のソート(単純挿入法) 
 * 引数 struct EDGBUF *DataStart: 並び替えの先頭ポインタ
 *      struct EDGBUF *DataEnd:   並び替える最終ポインタ
 * 戻り値 なし
 */
void InsertSort(struct EDGBUF *DataStart,struct EDGBUF *DataEnd)
{
    struct EDGBUF *GetData, *DataAddr;
    struct EDGBUF p;

    for ( GetData = DataEnd - 1 ; GetData >= DataStart ; GetData-- ) {
        p = *GetData;
        for ( DataAddr = GetData + 1 ; ( *DataAddr ).X < p.X ; DataAddr++ )
            *( DataAddr - 1 ) = *DataAddr;
        *( DataAddr - 1 ) = p;
    }
}

/**************
 *  ポリゴン描画メインルーチン 
 * 引数 int StartEdge: 辺リストのスタートアドレス
 *     int EndEdge: 辺リストの終了アドレス
 *     struct EDGBUF *EdgBuf:  辺リストアドレス格納用配列
 * 戻り値 なし
 */
void PolyFill(int win,int StartEdge,int EndEdge,struct EDGBUF *EdgBuf)
{
    int ActiveEdgePointer, NonActiveEdgePointer;
    struct EDGBUF ep, eof;
    int x,y;
    int x0,x1;
    int MINY=0,MAXY=400; //画面のサイズY方向
    int MINX=0,MAXX=400; //画面のサイズx方向

    eof.X = 0x7FFFFFFF;

    /* 全ての辺リストを「未アクティブ」にする */
    //NonActiveEdgePointer = EdgBufPointer;
    for (int dp = StartEdge ;dp < EndEdge ;dp++ ) {
        EdgBuf[dp-StartEdge] = EdgBuf[dp];
    }
    ActiveEdgePointer = NonActiveEdgePointer = EndEdge - StartEdge;
    /* 「アクティブ」な辺リストの末尾に番人を設ける(ソート時に必要) */
    EdgBuf[ActiveEdgePointer + 1 ] = eof;
    for ( y = MINY ; y <= MAXY ; y++ ) {
        /* yと始点が一致した「未アクティブ」な辺を「アクティブ」にする */
        for ( int i = 0 ; i <= NonActiveEdgePointer ; ) {
            if ( EdgBuf[i].Y0 == y ) {
                ep = EdgBuf[i];
                EdgBuf[i] = EdgBuf[NonActiveEdgePointer];
                EdgBuf[NonActiveEdgePointer--] = ep;
            } else i++;
        }

        /* yと終点が一致した「アクティブ」な辺を削除する */
        for ( int i = NonActiveEdgePointer + 1 ; i <= ActiveEdgePointer ; ) {
            if ( EdgBuf[i].Y1 == y ) {
                EdgBuf[i] = EdgBuf[ActiveEdgePointer];
                EdgBuf[ActiveEdgePointer--] = eof;
            } else i++;
        }

        /* 交点のソート */
        InsertSort( &EdgBuf[NonActiveEdgePointer + 1] , &EdgBuf[ActiveEdgePointer] );
        /* クリッピング・エリア外の交点をチェックしながらライン描画 */
        for ( int i = NonActiveEdgePointer + 1 ; i < ActiveEdgePointer ; i += 2 ) {
            x0 = EdgBuf[i].X;
            x1 = EdgBuf[i+1].X;
            if ( x1 < MINX || x0 > MAXX ) continue;
            if ( x0 < MINX ) x0 = MINX;
            if ( x1 > MAXX ) x1 = MAXX;
            for ( x = x0 ; x <= x1 ; x++ ) pset(win,x,y);
            /* X座標の更新 */
            EdgBuf[i].X += EdgBuf[i].a;
            EdgBuf[i+1].X += EdgBuf[i+1].a;
        }
    }
}

/**************
 *  ポリゴンを描画する 
 * 引数 int vnum: 頂点の数
 *     int *data: 頂点のリスト{ x0,y0,x1,y1,x2,y2...}
 * 戻り値 なし
 */
void polygonf(int win,int vnum,int *data)
{
    struct EDGBUF *buf;
    
    buf = (struct EDGBUF *)malloc(sizeof(struct EDGBUF)*(vnum));
    if(buf==NULL) {
        fprintf(stderr,"Memory allocation error\n");
        exit(EXIT_FAILURE);
    }
    GenerateEdgeList(vnum,data,buf);
    PolyFill(win,0,vnum-1,buf);
    free(buf);
}

int main(int argc, char **argv)
{
    int win;
    int data[]={10,10,300,50,300,300,350,350,150,300,350,200,10,10};

    gsetinitialattributes(DISABLE, BOTTOM_LEFT_ORIGIN); /*eggxの座標設定を通常のグラフィックスと同じに*/
    win = gopen(400,400); /* 400x400 ピクセルのグラフィックス用ウィンドゥを開く */
    //layer(win,0,1);
    newrgbcolor(win,255,0,0);

    polygonf(win,7,data);

    newrgbcolor(win,0,0,200);
    drawline(win,0,400,800,400);
    drawline(win,400,0,400,800);
    //copylayer(win,1,0);
    ggetch(); /* キー入力があるまで待つ */
    gclose(win); /* グラフィックス用ウィンドゥを閉じる */
}

実行結果

参考

扇形の描画

2020-05-26 20:35:35 | Linux
点を打つ関数pset()のみを使用して扇形(円弧)を描くプログラムを作成しました。基本となるアルゴリズム・プログラムはIoT-Kyoto.comの円弧を描いてみようを使わせてもらいました。円だけではなく楕円にも対応させています。グラフィックにはEGGX / ProCALLを使用しています。プログラムの作成はRaspberry Pi4で行っています。 

プログラムリスト
#include <stdio.h>
#include <math.h>
#include <eggx.h> /* EGGX を使う時に必要 */

/*************************
 * 角度を0〜2πの間に変換する
 *  引数 double angle: 角度
 * 戻り値 0〜2πの間の角度
 */
double Rangle(double angle)
{
    while(angle<0) angle += 2*M_PI;
    while(angle>=2*M_PI) angle -= 2*M_PI;
    return angle;
}

/***************************
 * 楕円と中心から角度angleで伸びる直線との交点を求める
 * 引数  int x: 中心のx座標
 *      int y: 中心のy座標
 *      int rx: x方向半径
 *      int ry: y方向半径
 *      int angle: 角度(0〜2π)
 *    int px: 交点x座標
 *      int py: 交点y座標
 * 戻り値 なし
 */
void calcArcPoint(int x,int y,int rx,int ry,double angled,int *px,int *py)
{
    double r,a,b;
    angled = Rangle(angled);

    r=1.0;
    a=1.0/((double)rx*(double)rx);
    b=1.0/((double)ry*(double)ry);
         
    if(angled==M_PI/2) {            //90度
        *px = x;
        *py = y - ry;
    } else if(angled==M_PI*3/2) { //270度
        *px = x;
        *py = y + ry;
    } else {
        double m = tan(angled);
        *px = sqrt((r*r)/(a + b * m*m));
        *py = sqrt((r*m*r*m)/(a + b * m*m));

        if(angled<M_PI/2) {
            *px = x + *px;
            *py = y - *py;
        } else if(angled<M_PI) {
            *px = x - *px;
            *py = y - *py;
        } else if(angled<M_PI*3/2) {
            *px = x - *px;
            *py = y + *py;
        } else {
            *px = x + *px;
            *py = y + *py;
        }
    }
}
 
/*************************
 * フレームバッファに楕円を描く
 *  引数 int cx,cy: 円の中心座標
 *     int rx: x方向の半径
 *       int ry: y方向の半径
 *       double Sangle: 描画スタート角度
 *       double Eangle: 描画終了角度
 * 戻り値 なし
 */
void grArc(int win,int cx, int cy, int rx,int ry, double Sangle,double Eangle)
{
    int dx, dy, s ;
    int x1, y1, x2, y2, x3, y3, x4, y4 ;
    int sx,sy,ex,ey;
    int psx, psy, pex, pey, ss, es, i, j ;
    unsigned int pass[4] ;

    calcArcPoint(cx,cy,rx,ry,Sangle,&sx,&sy);
    calcArcPoint(cx,cy,rx,ry,Eangle,&ex,&ey);
    psx = sx - cx ;
    pex = ex - cx ;
    psy = sy - cy ;
    pey = ey - cy ;
                                // 始点の象限
    if (psx >= 0) {
        if (psy >= 0) ss = 3 ;
        else          ss = 0 ;
    } else {
        if (psy >= 0) ss = 2 ;
        else          ss = 1 ;
    }
                                // 終点の象限
    if (pex >= 0) {
        if (pey >= 0) es = 3 ;
        else          es = 0 ;
    } else {
        if (pey >= 0) es = 2 ;
        else          es = 1 ;
    }

    if (ss == es) {                                     // 始点終点の象限が同じ
        if (((psy <  0) && (psx >= pex)) ||
            ((psy >= 0) && (psx <= pex))) {
            for (i = 0 ; i < 4 ; i++) pass[i] = 0 ;     // 小円( < 90 )
            pass[ss] = 5 ;
        } else {
            for (i = 0 ; i < 4 ; i++) pass[i] = 1 ;     // 大円( > 270 )
            pass[ss] = 4 ;
        }
    } else {
        for (i = 0 ; i < 4 ; i++) pass[i] = 0 ;
        j = ss ;
        for (i = 0 ; i < 4 ; i++) {
            pass[j] = 1 ;                               // 全表示
            if (j == es) break ;
            ++j ;
            if (j > 3) j = 0 ;
        }
        pass[ss] = 2 ;                                  // 始点のみ
        pass[es] = 3 ;                                  // 終点のみ
    }
    
    if(rx>ry) {
        dx = rx ;
        s = rx ;
        dy = 0 ;

        while (dx >= dy) {
            unsigned int  flag ;
            int dxx = dx*ry/rx;
            int dyy = dy*ry/rx;
            x1 = cx + dx;
            x2 = cx - dx;
            x3 = cx + dy;
            x4 = cx - dy;
            y1 = cy + dyy;
            y2 = cy - dyy; 
            y3 = cy + dxx;
            y4 = cy - dxx;
            

            flag = 0x00 ;
                                            // 第1象限
            switch (pass[0]) {
                default:
                    break ;
                case    1:
                    flag = 0x03 ;
                    break ;
                case    2:
                    if ((x1 <= sx) && (y2 <= sy)) flag |= 0x01 ;
                    if ((x3 <= sx) && (y4 <= sy)) flag |= 0x02 ;
                    break ;
                case    3:
                    if ((x1 >= ex) && (y2 >= ey)) flag |= 0x01 ;
                    if ((x3 >= ex) && (y4 >= ey)) flag |= 0x02 ;
                    break ;
                case    4:
                    if (((x1 <= sx) || (x1 >= ex)) && ((y2 <= sy) || (y2 >= ey))) flag |= 0x01 ;
                    if (((x3 <= sx) || (x3 >= ex)) && ((y4 <= sy) || (y4 >= ey))) flag |= 0x02 ;
                    break ;
                case    5:
                    if ((x1 <= sx) && (x1 >= ex) && (y2 <= sy) && (y2 >= ey)) flag |= 0x01 ;
                    if ((x3 <= sx) && (x3 >= ex) && (y4 <= sy) && (y4 >= ey)) flag |= 0x02 ;
                    break ;
            }
                                            // 第2象限
            switch (pass[1]) {
                default:
                    break ;
                case    1:
                    flag |= 0x0C ;
                    break ;
                case    2:
                    if ((x4 <= sx) && (y4 >= sy)) flag |= 0x04 ;
                    if ((x2 <= sx) && (y2 >= sy)) flag |= 0x08 ;
                    break ;
                case    3:
                    if ((x4 >= ex) && (y4 <= ey)) flag |= 0x04 ;
                    if ((x2 >= ex) && (y2 <= ey)) flag |= 0x08 ;
                    break ;
                case    4:
                    if (((x4 <= sx) || (x4 >= ex)) && ((y4 >= sy) || (y4 <= ey))) flag |= 0x04 ;
                    if (((x2 <= sx) || (x2 >= ex)) && ((y2 >= sy) || (y2 <= ey))) flag |= 0x08 ;
                    break ;
                case    5:
                    if ((x4 <= sx) && (x4 >= ex) && (y4 >= sy) && (y4 <= ey)) flag |= 0x04 ;
                    if ((x2 <= sx) && (x2 >= ex) && (y2 >= sy) && (y2 <= ey)) flag |= 0x08 ;
                    break ;
            }
                                            // 第3象限
            switch (pass[2]) {
                default:
                    break ;
                case    1:
                    flag |= 0x30 ;
                    break ;
                case    2:
                    if ((x2 >= sx) && (y1 >= sy)) flag |= 0x10 ;
                    if ((x4 >= sx) && (y3 >= sy)) flag |= 0x20 ;
                    break ;
                case    3:
                    if ((x2 <= ex) && (y1 <= ey)) flag |= 0x10 ;
                    if ((x4 <= ex) && (y3 <= ey)) flag |= 0x20 ;
                    break ;
                case    4:
                    if (((x2 >= sx) || (x2 <= ex)) && ((y1 >= sy) || (y1 <= ey))) flag |= 0x10 ;
                    if (((x4 >= sx) || (x4 <= ex)) && ((y3 >= sy) || (y3 <= ey))) flag |= 0x20 ;
                    break ;
                case    5:
                    if ((x2 >= sx) && (x2 <= ex) && (y1 >= sy) && (y1 <= ey)) flag |= 0x10 ;
                    if ((x4 >= sx) && (x4 <= ex) && (y3 >= sy) && (y3 <= ey)) flag |= 0x20 ;
                    break ;
            }
                                            // 第4象限
            switch (pass[3]) {
                default:
                    break ;
                case    1:
                    flag |= 0xC0 ;
                    break ;
                case    2:
                    if ((x3 >= sx) && (y3 <= sy)) flag |= 0x40 ;
                    if ((x1 >= sx) && (y1 <= sy)) flag |= 0x80 ;
                    break ;
                case    3:
                    if ((x3 <= ex) && (y3 >= ey)) flag |= 0x40 ;
                    if ((x1 <= ex) && (y1 >= ey)) flag |= 0x80 ;
                    break ;
                case    4:
                    if (((x3 >= sx) || (x3 <= ex)) && ((y3 <= sy) || (y3 >= ey))) flag |= 0x40 ;
                    if (((x1 >= sx) || (x1 <= ex)) && ((y1 <= sy) || (y1 >= ey))) flag |= 0x80 ;
                    break ;
                case    5:
                    if ((x3 >= sx) && (x3 <= ex) && (y3 <= sy) && (y3 >= ey)) flag |= 0x40 ;
                    if ((x1 >= sx) && (x1 <= ex) && (y1 <= sy) && (y1 >= ey)) flag |= 0x80 ;
                    break ;
            }

            if (flag & 0x01) pset(win,x1,y2) ;
            if (flag & 0x02) pset(win,x3,y4) ;
            if (flag & 0x04) pset(win,x4,y4) ;
            if (flag & 0x08) pset(win,x2,y2) ;
            if (flag & 0x10) pset(win,x2,y1) ;
            if (flag & 0x20) pset(win,x4,y3) ;
            if (flag & 0x40) pset(win,x3,y3) ;
            if (flag & 0x80) pset(win,x1,y1) ;

            s -= 2 * dy + 1 ;
            if (s < 0) {
                --dx ;
                s += 2 * dx ;
            }
            ++dy ;
        }
    } else {
        dx = 0 ;
        s = ry ;
        dy = ry ;

        while (dy >= dx) {
            unsigned int  flag ;
            int dxx = dx*rx/ry;
            int dyy = dy*rx/ry;
            x1 = cx + dxx;
            x2 = cx - dxx;
            x3 = cx + dyy;
            x4 = cx - dyy;
            y1 = cy + dy;
            y2 = cy - dy; 
            y3 = cy + dx;
            y4 = cy - dx;
            

            flag = 0x00 ;
                                            // 第1象限
            switch (pass[0]) {
                default:
                    break ;
                case    1:
                    flag = 0x03 ;
                    break ;
                case    2:
                    if ((x1 <= sx) && (y2 <= sy)) flag |= 0x01 ;
                    if ((x3 <= sx) && (y4 <= sy)) flag |= 0x02 ;
                    break ;
                case    3:
                    if ((x1 >= ex) && (y2 >= ey)) flag |= 0x01 ;
                    if ((x3 >= ex) && (y4 >= ey)) flag |= 0x02 ;
                    break ;
                case    4:
                    if (((x1 <= sx) || (x1 >= ex)) && ((y2 <= sy) || (y2 >= ey))) flag |= 0x01 ;
                    if (((x3 <= sx) || (x3 >= ex)) && ((y4 <= sy) || (y4 >= ey))) flag |= 0x02 ;
                    break ;
                case    5:
                    if ((x1 <= sx) && (x1 >= ex) && (y2 <= sy) && (y2 >= ey)) flag |= 0x01 ;
                    if ((x3 <= sx) && (x3 >= ex) && (y4 <= sy) && (y4 >= ey)) flag |= 0x02 ;
                    break ;
            }
                                            // 第2象限
            switch (pass[1]) {
                default:
                    break ;
                case    1:
                    flag |= 0x0C ;
                    break ;
                case    2:
                    if ((x4 <= sx) && (y4 >= sy)) flag |= 0x04 ;
                    if ((x2 <= sx) && (y2 >= sy)) flag |= 0x08 ;
                    break ;
                case    3:
                    if ((x4 >= ex) && (y4 <= ey)) flag |= 0x04 ;
                    if ((x2 >= ex) && (y2 <= ey)) flag |= 0x08 ;
                    break ;
                case    4:
                    if (((x4 <= sx) || (x4 >= ex)) && ((y4 >= sy) || (y4 <= ey))) flag |= 0x04 ;
                    if (((x2 <= sx) || (x2 >= ex)) && ((y2 >= sy) || (y2 <= ey))) flag |= 0x08 ;
                    break ;
                case    5:
                    if ((x4 <= sx) && (x4 >= ex) && (y4 >= sy) && (y4 <= ey)) flag |= 0x04 ;
                    if ((x2 <= sx) && (x2 >= ex) && (y2 >= sy) && (y2 <= ey)) flag |= 0x08 ;
                    break ;
            }
                                            // 第3象限
            switch (pass[2]) {
                default:
                    break ;
                case    1:
                    flag |= 0x30 ;
                    break ;
                case    2:
                    if ((x2 >= sx) && (y1 >= sy)) flag |= 0x10 ;
                    if ((x4 >= sx) && (y3 >= sy)) flag |= 0x20 ;
                    break ;
                case    3:
                    if ((x2 <= ex) && (y1 <= ey)) flag |= 0x10 ;
                    if ((x4 <= ex) && (y3 <= ey)) flag |= 0x20 ;
                    break ;
                case    4:
                    if (((x2 >= sx) || (x2 <= ex)) && ((y1 >= sy) || (y1 <= ey))) flag |= 0x10 ;
                    if (((x4 >= sx) || (x4 <= ex)) && ((y3 >= sy) || (y3 <= ey))) flag |= 0x20 ;
                    break ;
                case    5:
                    if ((x2 >= sx) && (x2 <= ex) && (y1 >= sy) && (y1 <= ey)) flag |= 0x10 ;
                    if ((x4 >= sx) && (x4 <= ex) && (y3 >= sy) && (y3 <= ey)) flag |= 0x20 ;
                    break ;
            }
                                            // 第4象限
            switch (pass[3]) {
                default:
                    break ;
                case    1:
                    flag |= 0xC0 ;
                    break ;
                case    2:
                    if ((x3 >= sx) && (y3 <= sy)) flag |= 0x40 ;
                    if ((x1 >= sx) && (y1 <= sy)) flag |= 0x80 ;
                    break ;
                case    3:
                    if ((x3 <= ex) && (y3 >= ey)) flag |= 0x40 ;
                    if ((x1 <= ex) && (y1 >= ey)) flag |= 0x80 ;
                    break ;
                case    4:
                    if (((x3 >= sx) || (x3 <= ex)) && ((y3 <= sy) || (y3 >= ey))) flag |= 0x40 ;
                    if (((x1 >= sx) || (x1 <= ex)) && ((y1 <= sy) || (y1 >= ey))) flag |= 0x80 ;
                    break ;
                case    5:
                    if ((x3 >= sx) && (x3 <= ex) && (y3 <= sy) && (y3 >= ey)) flag |= 0x40 ;
                    if ((x1 >= sx) && (x1 <= ex) && (y1 <= sy) && (y1 >= ey)) flag |= 0x80 ;
                    break ;
            }

            if (flag & 0x01) pset(win,x1,y2) ;
            if (flag & 0x02) pset(win,x3,y4) ;
            if (flag & 0x04) pset(win,x4,y4) ;
            if (flag & 0x08) pset(win,x2,y2) ;
            if (flag & 0x10) pset(win,x2,y1) ;
            if (flag & 0x20) pset(win,x4,y3) ;
            if (flag & 0x40) pset(win,x3,y3) ;
            if (flag & 0x80) pset(win,x1,y1) ;

            s -= 2 * dx + 1 ;
            if (s < 0) {
                --dy ;
                s += 2 * dy ;
            }
            ++dx ;
        }
    }
}

int main(int argc, char **argv)
{
    int win;
    gsetinitialattributes(DISABLE, BOTTOM_LEFT_ORIGIN); /*eggxの座標設定を通常のグラフィックスと同じに*/
    win = gopen(400,400); /* 400x400 ピクセルのグラフィックス用ウィンドゥを開く */
    newrgbcolor(win,255,0,0);
    grArc(win,200,200,150,80,0,M_PI/3);
    grArc(win,200,200,160,90,M_PI/3,M_PI*2/3);
    grArc(win,200,200,170,100,M_PI*2/3,M_PI);
    grArc(win,200,200,160,90,M_PI,M_PI*4/3);
    grArc(win,200,200,170,100,M_PI*4/3,M_PI*5/3);
    grArc(win,200,200,160,90,M_PI*5/3,0);
    newrgbcolor(win,0,255,0);
    grArc(win,200,200,100,150,0,M_PI);
    grArc(win,200,200,50,100,M_PI,0);
    grArc(win,200,200,75,125,M_PI/2,-M_PI/2);
    newrgbcolor(win,0,0,200);
    drawline(win,0,200,400,200);
    drawline(win,200,0,200,400);

    ggetch(); /* キー入力があるまで待つ */
    gclose(win); /* グラフィックス用ウィンドゥを閉じる */
    
    return 0;
}

実行結果


参考

キー入力を受け取る

2020-04-30 20:47:04 | Linux
C言語ではキー入力を受け取るときに最後に[Enter]キーを押す必要があります。[Enter]キーを押さなくてもキー入力を受け取るプログラムのサンプルです。同じことはncurses ライブラリでもできますが、キー入力のみでよい場合は、このプログラムを組み込むだけでOKです。プログラムの作成はRaspberry Pi4で行っています。 

#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>

/*
 * 押されたキーの値を返す
 * ブロックしない。キーが押されていない場合は戻り値は0となる。
 */
int getkeyNB(void)
{
    struct termios oldt, newt;
    int ch0,ch1,ch2,ch3,ch4;
    int ret,oldf;

    tcgetattr(STDIN_FILENO, &oldt);
    newt = oldt;
    newt.c_iflag = ~( BRKINT | ISTRIP | IXON  );
    newt.c_lflag = ~( ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHONL );
    newt.c_cc[VTIME]    = 0;     /* キャラクタ間タイマを使わない */
    newt.c_cc[VMIN]     = 1;     /* 1文字来るまで,読み込みをブロックする */
    //newt.c_cc[VINTR]    = 0;     /* Ctrl-c */ 
    //newt.c_cc[VQUIT]    = 0;     /* Ctrl-\ */
    //newt.c_cc[VERASE]   = 0;     /* del */
    //newt.c_cc[VKILL]    = 0;     /* @ */
    //newt.c_cc[VEOF]     = 4;     /* Ctrl-d */
    //newt.c_cc[VSWTC]    = 0;     /* '\0' */
    //newt.c_cc[VSTART]   = 0;     /* Ctrl-q */ 
    //newt.c_cc[VSTOP]    = 0;     /* Ctrl-s */
    //newt.c_cc[VSUSP]    = 0;     /* Ctrl-z */
    //newt.c_cc[VEOL]     = 0;     /* '\0' */
    //newt.c_cc[VREPRINT] = 0;     /* Ctrl-r */
    //newt.c_cc[VDISCARD] = 0;     /* Ctrl-u */
    //newt.c_cc[VWERASE]  = 0;     /* Ctrl-w */
    //newt.c_cc[VLNEXT]   = 0;     /* Ctrl-v */
    //newt.c_cc[VEOL2]    = 0;     /* '\0' */    
    if(tcsetattr(STDIN_FILENO, TCSANOW, &newt)==-1) {
        fprintf(stderr,"error tcsetattr\n");
        exit(EXIT_FAILURE);
    }
    /* ノンブロックモードに設定 */
    oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
    if(oldf<0) {
        fprintf(stderr,"error fcntl\n");
        exit(EXIT_FAILURE);
    }   
    if(fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK)<0) {
        fprintf(stderr,"error fcntl\n");
        exit(EXIT_FAILURE);
    }   
    
    ch0 = getchar();
    if(ch0==0x1B) {  //矢印キー Fnキーなどの取得 取得できないキーもある
        ch1 = getchar();
        ch2 = getchar();
        if(ch2==0x32) {
            ch3 = getchar();
            if(ch3==0x7e) {
                ret = (ch0<<24) | (ch1<<16) | (ch2<<8) | ch3;
            } else {
                ch4 = getchar();
                ret = (ch1<<24) | (ch2<<16) | (ch3<<8) | ch4;
            }
        } else if(ch2==0x31) {
            ch3 = getchar();
            ch4 = getchar();
            ret = (ch1<<24) | (ch2<<16) | (ch3<<8) | ch4;
        } else if((ch2==0x33)||(ch2==0x35)||(ch2==0x36)) {
            ch3 = getchar();
            ret = (ch0<<24) | (ch1<<16) | (ch2<<8) | ch3;
        } else {
            ret = (ch0<<16) | (ch1<<8) | ch2;
        }
    } else if(ch0 != EOF) {
        ret = ch0;
    } else {
        ret = 0;
    }

    if(tcsetattr(STDIN_FILENO, TCSANOW, &oldt)==-1) {
        fprintf(stderr,"error tcsetattr\n");
        exit(EXIT_FAILURE);
    }
    if(fcntl(STDIN_FILENO, F_SETFL, oldf)<0) {
        fprintf(stderr,"error fcntl\n");
        exit(EXIT_FAILURE);
    }           
    if(ret == 0x03) { //[Ctrl]+[C] で割り込み発生
        pid_t pid = getpid();
        kill(pid, SIGINT);
    }
    /*if(ret == 0x1a) { //[Ctrl]+[Z] で割り込み発生
        pid_t pid = getpid();
        kill(pid, SIGTSTP);
    }*/
    return ret;
}


/*
 * 押されたキーの値を返す
 * ブロックする。キーが押されるまで戻らない。
 */
int getkey(void)
{
    struct termios oldt, newt;
    int ch0,ch1,ch2,ch3,ch4;
    int ret;

    tcgetattr(STDIN_FILENO, &oldt);
    newt = oldt;
    newt.c_iflag = ~( BRKINT | ISTRIP | IXON  );
    newt.c_lflag = ~( ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHONL );
    newt.c_cc[VTIME]    = 0;     /* キャラクタ間タイマを使わない */
    newt.c_cc[VMIN]     = 1;     /* 1文字来るまで,読み込みをブロックする */
    if(tcsetattr(STDIN_FILENO, TCSANOW, &newt)==-1) {
        fprintf(stderr,"error tcsetattr\n");
        exit(EXIT_FAILURE);
    }
    
    ch0 = getchar();
    if(ch0==0x1B) {  //矢印キー Fnキーなどの取得 取得できないキーもある
        ch1 = getchar();
        ch2 = getchar();
        if(ch2==0x32) {
            ch3 = getchar();
            if(ch3==0x7e) {
                ret = (ch0<<24) | (ch1<<16) | (ch2<<8) | ch3;
            } else {
                ch4 = getchar();
                ret = (ch1<<24) | (ch2<<16) | (ch3<<8) | ch4;
            }
        } else if(ch2==0x31) {
            ch3 = getchar();
            ch4 = getchar();
            ret = (ch1<<24) | (ch2<<16) | (ch3<<8) | ch4;
        } else if((ch2==0x33)||(ch2==0x35)||(ch2==0x36)) {
            ch3 = getchar();
            ret = (ch0<<24) | (ch1<<16) | (ch2<<8) | ch3;
        } else {
            ret = (ch0<<16) | (ch1<<8) | ch2;
        }
    } else if(ch0 != EOF) {
        ret = ch0;
    } else {
        ret = 0;
    }

    if(tcsetattr(STDIN_FILENO, TCSANOW, &oldt)==-1) {
        fprintf(stderr,"error tcsetattr\n");
        exit(EXIT_FAILURE);
    }
    if(ret == 0x03) { //[Ctrl]+[C] で割り込み発生
        pid_t pid = getpid();
        kill(pid, SIGINT);
    }

    return ret;
}

int main(int argc,char *argv[])
{
    int key;

    while (1) {
        //key = getkeyNB();
        key = getkey();
        if (key!=0) {
            printf("key code %4x\n",key);
        }else{
            printf("wait\n");
            usleep(100000);
        }
            
    }

    return 0;
}

参考

ncursesのサンプルプログラム

2020-04-22 19:54:15 | Linux
ncurses は、端末に依存しない形式でテキストユーザインタフェース (TUI) を作成するためのライブラリです。ncursesのサンプルプログラムを集めてみました。リストはリンク先からの借り物です。 プログラムの作成はRaspberry Pi4で行っています。

インストールとコンパイル
インストール
$ sudo apt install libncurses-dev
コンパイル
$ gcc -o hoge hoge.c -lncurses

リスト1
#include <ncurses.h>
#include <stdio.h>
#include <string.h>

int main(int argc,char *argv[]) 
{
  initscr();//初期化
  noecho(); //キーが入力されても表示しない
  curs_set(0);//カーソルを非表示
  mvprintw(12, 30, "Hello World!");
  while (true) {
    int ch = getch();
    if (ch == 'q') break;
  }
  endwin();//終了処理
  retuen 0;
}

リスト2
#include <ncurses.h>
#include <stdio.h>
#include <string.h>

int main(int argc,char *argv[]) 
{
    int  x, y, w, h;
    char *str="Hello World";
    int  key;

    initscr();//初期化
    noecho();//キー入力した文字の非表示モード
    curs_set(0);//カーソルを非表示
    cbreak();//[Enter] キー不要の入力モード
    keypad(stdscr, TRUE);//特殊キー(カーソルキーなど)を有効化
    //stdscr は端末画面を表わす定数である. 標準出力 stdout の curses 版だと考えればよい.
    getmaxyx(stdscr, h, w);//端末のサイズを取得 注意 ポインタ渡しではない
    y = h/2;
    x = (w-strlen(str))/2;

    while (1) {
        erase();//画面の消去
        move(y, x);//表示位置指定
        addstr(str);//文字を出力する
        refresh();//画面の再表示

        key = getch();//キー入力
        if (key == 'q') break;
        switch (key) {
        case KEY_UP:    y--; break;
        case KEY_DOWN:  y++; break;
        case KEY_LEFT:  x--; break;
        case KEY_RIGHT: x++; break;
        }
    }
    endwin();//終了処理
    return 0;
}


リスト3
#include <ncurses.h>
#include <stdio.h>
#include <string.h>

int main(int argc,char *argv[]) 
{
    // 端末の準備
    initscr();

    // 色の準備
    start_color();
    init_pair(1, COLOR_RED, COLOR_BLUE);    // 色1 は青地に赤文字
    init_pair(2, COLOR_GREEN, COLOR_BLUE);  // 色2 は青地に緑文字
    init_pair(3, COLOR_YELLOW, COLOR_BLUE); // 色3 は青地に黄文字
    init_pair(10, COLOR_WHITE, COLOR_BLUE); // 色10 は青地に白文字
    bkgd(COLOR_PAIR(10));           // 背景は色10

    // 表示
    attrset(COLOR_PAIR(1));         // 色1 を使う
    mvaddstr(5,  5, "Hello World");
    attrset(COLOR_PAIR(2));         // 色2 を使う
    mvaddstr(5, 25, "Hello World");
    attrset(COLOR_PAIR(3));         // 色3 を使う
    mvaddstr(5, 45, "Hello World");

    attrset(COLOR_PAIR(1) | A_BOLD);        // 色&強調表示
    mvaddstr(6,  5, "Hello World");
    attrset(COLOR_PAIR(2) | A_BOLD);
    mvaddstr(6, 25, "Hello World");
    attrset(COLOR_PAIR(3) | A_BOLD);
    mvaddstr(6, 45, "Hello World");

    attrset(COLOR_PAIR(1) | A_REVERSE);     // 色&反転表示
    mvaddstr(7,  5, "Hello World");
    attrset(COLOR_PAIR(2) | A_REVERSE);
    mvaddstr(7, 25, "Hello World");
    attrset(COLOR_PAIR(3) | A_REVERSE);
    mvaddstr(7, 45, "Hello World");

    attrset(COLOR_PAIR(1) | A_REVERSE | A_BOLD);    // 色&反転&強調
    mvaddstr(8,  5, "Hello World");
    attrset(COLOR_PAIR(2) | A_REVERSE | A_BOLD);
    mvaddstr(8, 25, "Hello World");
    attrset(COLOR_PAIR(3) | A_REVERSE | A_BOLD);
    mvaddstr(8, 45, "Hello World");

    // 終了
    getch();

    endwin();
    return (0);
}

参考