お知らせ

  • 利用規約を守って投稿してください。また、よくある質問および投稿の手引きも参照してください。
  • メッセージの投稿にはアカウントが必要です。未登録の方は、ユーザ登録ページからアカウントを作成することができます。

#1 2009-04-15 15:02:50

YIS
メンバ
登録日: 2009-03-29

[解決済]C言語で点や線を描画するにはどうすれば?

投稿はこちらの「開発環境」で良いのか散々悩みましたが、こちらに書き込みます。問題があれば移動してください。^^;

さて、basic-256(synapticで発見してインストールしました)で書いたソースコードをC言語に移植しようと思っています。C言語自体は以前から興味があり(その頃はWindows版でしたが)、本のとおりにプログラムを書いては実行していました。しかし訳あって中断していました。

basic-256では表示色が簡単になっているようです。できればubntuに付属の一部のスクリーンセーバーにある表現のように多くの色を使って表現したいと思っています。(昔のBASICならば、7〜8ビットくらいで擬似多色表現できていたような気もします)

C言語は今学習中です。CUI上で点や線の描画ができるようでしたらそちらの方が良いのですが、フォーラム検索ではどうもそのような方法が無いように見受けられました。その時の検索にかかったスレッドで、GTKを使うと良いみたいな事が書かれていたので少し調べてみました。

wikipediaでは、(一部抜粋)

GTK+だけでもアプリケーションを構成することは可能である。

と書かれていました。(私はアプリケーションの構成といったレベルまでは考えて無いです。ただbasic-256のソースコードをC言語に移植できれば(今のところは)良いだけなので)

そこでsynapticで"GTK"で検索しましたが、どれを導入すれば良いのかわからなかったです。:(

日本GNOMEの会のホームページも見てみましたが活動休止のようでした。また、内容もアプリケーション開発に重点が置かれているように思えました。

何度も書きますが、私は、「点や線の描画、色の多色化」をC言語で表現してみたいのです。GTKを調べたりしていましたが全く見当外れの方向性だったでしょうか?

参考までにbasic-256で書いたソースコードを載せておきます。

コード:

#kyuu - sakusei

#syoki syori
cls
clg
fastgraphics
# kakudai-teisuu
hougan = 15

# byouga-ryouiki
gmax = 300
gmin = 0

#zahyoujiku(x,y)
xplus = 105
yplus = 120

#hougansi-byouga
color darkgrey
for i = gmin to gmax step hougan
  line 0,i,gmax,i
  line i,0,i,gmax
next i 

#(x,y)zahyoujiku-wo-egakku
color black
line gmin,gmax-yplus,gmax,gmax-yplus
line gmin+xplus,gmax,gmin+xplus,gmin

#kokokaa main pg
r = 5  # hankei
kstep = 1/hougan  #for-next no step suu
print kstep
gosa = 0.1 # kyuu hyoumen ka douka no hantei ji no gosa
min=0   # hansyakaku saitei chi kakudo(si-ta)
max=0  #hanasyakaku saiddai chi kakudo(si-ta)

#kougen
kox = 9
koy = 9
koz = 15
color orange
#kougen no basyo wo simesu (z-jiku ha kouro site imasen ^^;)
circle kox*hougan + xplus , gmax - koy*hougan-yplus,3


#--- main ru-chin ---
#zahyou(x,y,z) ga kyuu hyoumen ka douka siraberu(dorokusai houhou de sumima sen ^^;)
for z=0 to r step kstep
  for y=-r to r step kstep
      for x=-r to r step kstep
    dumy = x^2 + y^2 + z^2
    if ((dumy <= r^2+gosa) and (dumy>=r^2-gosa)) then   gosub pset
    next x
  next y
  refresh
#goto endhing
next z
#--- main ru-chin owari ---


endhing:
refresh
print"MAX=";
print max
print"MIN=";
print min
end


pset:
#gosub kyuubekutoru
gosub kakudo
if cosin>0 then color grey
if cosin<0 then color darkblue
if cosin<-0.1 then  color blue
if cosin<-0.2 then color green
if cosin<-0.3 then color darkgreen
if cosin<-0.4 then color red
if cosin<-0.5 then color darkred
if cosin<-0.6 then color darkpurple
if cosin<-0.7 then color purple
if cosin<-0.8 then color darkcyan
if cosin<-0.9 then color cyan
if cosin<-0.92then color darkyellow
if cosin<-0.93 then color yellow
if cosin<-0.94 then  color darkorange
if cosin<-0.95 then color orange
if cosin<-0.96 then color darkgrey
if cosin<-0.97 then color black
plot x * hougan + xplus, gmax - y * hougan - yplus
return





#p-bekuoru wo byouga
kyuubekutoru:
color darkyellow
  line x*hougan +xplus , gmax - y*hougan - yplus, x*2*hougan +xplus , gmax - y*2*hougan - yplus
return






#kougen tono kakudo (si-ta) wo motomeru
kakudo:
#A = x*(x-kox)+y*(y-koy)+koz^2
A = x*(x-kox)+y*(y-koy)+z*(z-koz)
c=(x)^2+(y)^2+(z)^2
gosub SQR
B = xn
#c=kox^2+koy^2+koz^2
c=(x-kox)^2+(y-koy)^2+(z-koz)^2
gosub SQR
D = xn

cosin = A/(B*D)
#print cosin
if cosin>min then min=cosin
if cosin<max then max=cosin
return




#heihoukon wo motomeru
# " sousaku program " san no tokoro no nyu-ton kinnji wo tukawasete itadaite imasu(kansya!)
SQR:
#c=169
n=10
xn=0

xnloop:
if (xn*xn>=c) then  goto xnexit
xn = xn+ 1
goto xnloop
xnexit:

for i=0 to 10
  if i>=n then goto SQRend
  if i<n then xn=(xn+c/xn)/2
next i 

SQRend:
return

(たたき台のソースなのでまだまだ改良したいと思っています。)実はC言語のsqrt関数なども使いたいと思っています。^^;

eclipseは以前、インストールしたことがありますが、挙動が重すぎてほぼ作業できない状態です。今書き込みしているPCではGUIが重いですが、(Firefox起動に10秒前後です)eclipseは重いなどというレベルではなかったかと思います。今はeclipseは削除しています

アマゾンのホームページっで、和書のところも見てみました。(GTK関係で)
新品で1500〜2000円くらいなら購入を考えたと思いますが、高額の本ばかりで手がでません。

今もう一度フォーラムを検索すると「Wine」というWindows APIを使うプログラム群?があるようです。こらは私が勝手に仮想化ソフトと誤認していたかもしれません。しかしながら私の環境は純粋なubuntu 8.04.2 LTS環境なので関係がないような気もします。関係あったらすみません^^;


どなたかお力をお貸しください。お願いします。

最後の編集者: YIS (2009-04-22 19:59:00)

オフライン

 

#2 2009-04-15 15:09:59

hito
管理者
登録日: 2007-03-18

Re: [解決済]C言語で点や線を描画するにはどうすれば?

GTKではなく、おそらくお望みのものは「cairo」です。

cairoはGTKのバックエンドになる描画系のライブラリで、平面に対する描画を抽象化してくれます。使い方は普通にGoogleで検索すれば出てくると思います。

オフライン

 

#3 2009-04-15 16:17:01

YIS
メンバ
登録日: 2009-03-29

Re: [解決済]C言語で点や線を描画するにはどうすれば?

素早いレスありがとうございます。

「cairo」を調べていました。(するとRubyのページにたどり着いたり・・・^^;)

続きは明日になるかもしれません。いつも回答いただき感謝しています。本当にありがとうございます。:)

オフライン

 

#4 2009-04-16 03:37:38

okamrua
メンバ
From: 福岡
登録日: 2008-07-11

Re: [解決済]C言語で点や線を描画するにはどうすれば?

hitoさん>

cairo、なかなか使い良さそうですね。手早く2次元系のグラフィックをするには便利そうです。
私の場合、今まではXのライブラリを使ったり、Tcl/TkとかGladeとかOpenGLとかばっかりだったので、存在を知りませんでした。
良い情報ありがとうございます。

YISさん>

ソースコード見せていただきました。とてもおもしろかったですYO!
次回作期待してます^^

cairo Wikipedia
http://ja.wikipedia.org/wiki/Cairo

cairo本家
http://cairographics.org/
ただし、本家の中でもDocumentationのコーナーが結構分かりやすいです。
http://cairographics.org/documentation/

最後の編集者: okamrua (2009-04-16 03:39:34)

オフライン

 

#5 2009-04-16 12:22:33

YIS
メンバ
登録日: 2009-03-29

Re: [解決済]C言語で点や線を描画するにはどうすれば?

okamruaさん、こんにちは。レスありがとうございます。:)

X Window System、Tcl/Tk、OpenGLを少しですがさっきまで調べていました。Gladeは検索の仕方が悪いせいかよくわからなかったです。

okamruaさん による投稿:

ソースコード見せていただきました。とてもおもしろかったですYO!
次回作期待してます^^

ありがとうございます。:)
コードを書き込むかどうか、かなり悩みましたがおそらく「私が何をしたいのか」が分かりづらいと思い、書き込みました。恥ずかしいかぎりです。次回作はまだ考えていないですが、移植が終わったら何かすると思います。期待しないで待っていてくださいね。

URLによる誘導ありがとうございます。:)

現状報告など
現在、
http://cairographics.org/FAQ/
の、「Getting Started」>「What would a minimal C program look like using cairo?」のソースをコピーして動かそうとしています。pngファイルはこちらで用意しました。cairoのインストールもできているかと思います。

$ sudo apt-get install libcairo2-dev

インストール前のエラーが全く無くなり、実行ファイルができました。

しかし、ここで問題が発生しています。
/usr/lib/pkgconfigにPATHを通しているつもりですが実行ファイルが動作しません。

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/lib/pkg-config:/usr/lib/pkgconfig

二つ入力しているのは、pkgconfigかpkg-configなのか判断がつかなかったためです。(実際はpkgconfigの方が正しいようです)bashなどでexportしているわけではなく、手入力でやっています。

cc -o hello $(pkg-config --cflags --libs cairo) hello.c

でコンパイルしています。
実行は、

./hello

でよろしいですよね?

何も表示されないのが正常な出力結果なのでしょうか?(と書き込む直前まで思っていました。しかし、)

今気づきました。ファイルブラウザで見ると「Hello, world」のpng画像に置き換わっています。PNGファイルを用意するのではなく、PNGファイルを出力するプログラムだったんですね!凹みます。

今から他のサンプルプログラムを実行してみようと思います。

最後の編集者: YIS (2009-04-16 12:26:45)

オフライン

 

#6 2009-04-17 00:06:03

okamrua
メンバ
From: 福岡
登録日: 2008-07-11

Re: [解決済]C言語で点や線を描画するにはどうすれば?

キャンバスに色々使えるみたいなので、まずそれから決めないと先に進まないですね^^;

基礎のXlib
無難なGTK
もしくは、SDL
いやいやオレは OpenGL

さぁ、どれにしたのかな?

オフライン

 

#7 2009-04-18 07:26:23

YIS
メンバ
登録日: 2009-03-29

Re: [解決済]C言語で点や線を描画するにはどうすれば?

okamruaさん、おはようございます。返信が遅れて申し訳ないです。今必死にC言語の勉強中です。

cairoで作成しようと思ったのですが、実はWindow_Create?のところですでにつまずいていまして、基礎から勉強する必要性を感じC言語の勉強をしています。

現在gets関数のところを勉強中です。(gets関数を使うと警告!?が出ます。gccでは使わない方がいいのかもしれません!?)今日は先に進みたいと思っています。

Xlibが基礎ならば、Xlibを使いたいですね。X Window Systemのポリシー?は私も共感するところがありますので。(実はキャンバスの意味もよくわかっていませんが・・・)GTKでどのようにWindowを作るのかも知りません。^^;

勉強中ですので、もう少しお待ちくださいね。

オフライン

 

#8 2009-04-19 06:24:44

YIS
メンバ
登録日: 2009-03-29

Re: [解決済]C言語で点や線を描画するにはどうすれば?

途中経過です。

C言語の本はひととおり読みました。しかしC言語は難しいところが多く、本の内容全ての把握は無理でした。:(

今X-Windowでウィンドウを作ってみました。参考にさせていただいたサイトは「Yet Another Ruby Beginner」さん、「X-Window Programming」さん、「Xlib - Wikipedia」の編集者 さんです。他にもubuntu関係や他のサイトさんも参考にさせていただきました。ありがとうございます。:)

備忘録にウィンドウ生成のコードを書いておきます。改良したので少しはましになったかもです。(自信なし)

コード:

// 「Yet Another Ruby Beginner」さん、「X-Window Programming」さん、「Xlib - Wikipedia」の編集者 さんを参考にさせていただきました。感謝です!^^
// Xlibによるウィンドウの描画(改良版)

#include<stdio.h>
#include<X11/Xlib.h>
#include<stdlib.h>
#include<string.h>

int main (int argc, char *argv[])
{
// 変数?の宣言
    XEvent evt;
    Display *dpy;
    Window win,root_win;

    dpy = XOpenDisplay(NULL);        //X-Windowとの接続
    if (dpy == NULL) {
        printf("Disply がオープンできません\n");
        exit(1);
    }

// ウィンドウ作成
    root_win=DefaultRootWindow(dpy);
    win = XCreateSimpleWindow( dpy, root_win, 50 , 50 , 600, 500, 2, BlackPixel(dpy,0), WhitePixel(dpy,0));

// 受け付けるイベントの種類を選択
    XSelectInput(dpy, win, ExposureMask | KeyPressMask);

// ウィンドウ表示
    XMapWindow(dpy,win);
    XFlush(dpy);

// イベントループ
    while(1) {
        XNextEvent(dpy, &evt);

        if(evt.type == KeyPress)    //キー押下で終了
            break;
    }

    XDestroyWindow(dpy,win);    // ウィンドウの消滅
    XCloseDisplay(dpy);        //X-Windowとの接続解除

    return 0;
}

これからcairoで描画に挑戦です!

追伸
もう少しXlibを調べるかもしれません。

最後の編集者: YIS (2009-04-19 11:39:21)

オフライン

 

#9 2009-04-21 08:01:59

YIS
メンバ
登録日: 2009-03-29

Re: [解決済]C言語で点や線を描画するにはどうすれば?

皆さんおはようございますYISです。okamuraさん、Xlibを教えていただきありがとうございました。Xlibで検索して自分的にはかなり進展できたと思います。

現在の状況は、X-Windowで図形を表示。(「Xlib Programming Lectures」さん、「Yet Another Ruby Beginner」さんありがとうございます。^^)その後Cairoのサンプルソースを少し付け加えました。

まだまだ改良しようと思います。Cairo公式サイトのサンプルソースをひととおり実行するのが次の目標です。

たたき台のコードです。

コード:

// 「Xlib Programming Lectures」さんのサイトを参考にさせていただいてます。ありがとうございます!!^^
// コンパイル cc -o hello $(pkg-config --cflags --libs cairo) hello.c
// XとCariroが混在しています。
// 改良中です。まだ不完全です。(>_<

#include<stdio.h>
#include<stdlib.h>        // exit()関数用
#include<math.h>    // M_PIが必要なため
//#include<X11/Xlib.h>
#include <cairo.h>
#include <cairo-xlib.h>


#define WIN_W     600  /* ウィンドウの幅   */
#define WIN_H     400  /* ウィンドウの高さ */
#define WIN_X     0.0  /* ウィンドウ表示位置(X) */
#define WIN_Y     0.0  /* ウィンドウ表示位置(Y) */
#define BORDER    2    /* ボーダの幅      */
#define CIRCLE_W  100  /* 円が内接する正方形の幅 */
#define CIRCLE_H  100  /* 円が内接する正方形の高さ */
#define CIRCLE_X  200  /* 円の中心の X 座標 */
#define CIRCLE_Y  180  /* 円の中心の Y 座標 */

static void draw( Display* dpy, Window win, GC gc,unsigned long bcolor, cairo_surface_t *surface);


int 
main( void )
{
    Display*       dpy;         /* ディスプレイ */
    Window         root;        /* ルートウィンドウ */
    Window         win;         /* 表示するウィンドウ */
    int            screen;      /* スクリーン */
    unsigned long  black,white; /* 黒と白のピクセル値 */
    GC             gc;          /* グラフィックスコンテキスト */
    XEvent         evt;         /* イベント構造体 */

    Colormap       cmap;        /* カラーマップ */
    XColor         color, exact;
    unsigned long    bcolor=0;        // 色を変化させる(初期値は黒)
    cairo_surface_t *surface;        //cairoの構造体の中のひとつ!?


    /* Xサーバと接続する */
    dpy = XOpenDisplay( "" );
    if (dpy == NULL) {
        printf("Disply がオープンできません\n");
        exit(1);
    }


    /* ディスプレイ変数の取得 */
    root   = DefaultRootWindow( dpy );    //デフォルト・ウィンドウ
    screen = DefaultScreen( dpy );


    /* XAllocNamedColor() のためにカラーマップを取得 */
    cmap   = DefaultColormap( dpy, screen ); 


    /* 白、黒のピクセル値を取得 */
    white  = WhitePixel( dpy, screen );
    black  = BlackPixel( dpy, screen );

    /* ウィンドウを作成する。この時点ではまだ画面に表示されない。*/
    win = XCreateSimpleWindow( dpy, root,
           WIN_X, WIN_Y, WIN_W, WIN_H, BORDER, black, white);


    /* グラフィックスコンテキストを作る */
    gc = XCreateGC( dpy, win, 0, NULL );


    /* Xサーバから通知してもらうイベントを指定
       ここではキー押下イベントの他に Expose イベントを選択している */
    // マウスクリック追加
    XSelectInput( dpy, win, ButtonPressMask | KeyPressMask | ExposureMask);


    /* ウィンドウを画面に表示する(マップする)。 */
    XMapWindow( dpy, win );

    // ウィンドウのタイトル
    XStoreName(dpy, win, "draw with X and Cairo");


//    visual = cairo_xlib_surface_get_visual(surface);
//NG?
//    surface=cairo_xlib_surface_create(dpy, win,    visual, 200, 200);

//OK
surface=cairo_xlib_surface_create(dpy, win, DefaultVisual(dpy, 0), 200, 200);

/* Xサーバからイベントを読み込んで随時処理していくイベントループ */
    while(1) {

        XNextEvent( dpy, &evt );

        // イベント判定(キー入力で終了)
        switch( evt.type ) {
                case Expose:      
                    if ( evt.xexpose.count == 0 ) {
                        draw( dpy, win, gc, bcolor, surface );
                    }
                    break;

                case ButtonPress:
                    bcolor=bcolor+0xee;
                    if (bcolor >= 0xFFFFFF)
                        bcolor=0;
                    draw( dpy, win, gc, bcolor, surface);
                    break;
    
                case KeyPress:
                    // cairoリソースの解放 */
                    cairo_surface_destroy(surface);

                    // X-Window リソース解放
                    XFreeGC( dpy, gc );
                    XDestroyWindow( dpy, win );
                    XCloseDisplay( dpy );
                    return 0;
            }

    } // whileループ

}    //main()の終わり




// 描画ルーチン
static void
draw( Display* dpy, Window win, GC gc,unsigned long bcolor, cairo_surface_t *surface)
{
    /* 描画色を設定 */
    XSetForeground( dpy, gc, bcolor );

    /* 円の描画 */
    XFillArc( dpy, win, gc, 
          CIRCLE_X, CIRCLE_Y, CIRCLE_W, CIRCLE_H, 
          0, 360 * 64 );

//ここからcairoでの描画です
    cairo_t *cr;
    cr = cairo_create (surface);

//文字列描画
    cairo_set_font_size (cr, 15.0);
    cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
    cairo_move_to(cr, 10.0, 20.0);
    cairo_show_text(cr, "Hello X-Window and Cairo !");
    cairo_show_page(cr);

//    double M_PI = 3.1415926535;
    double xc = 125.0;
    double yc = 50.0;
    double radius = 100.0;
    double angle1 = 45.0  * (M_PI/180.0);    /* angles are specified */
    double angle2 = 180.0 * (M_PI/180.0);  /* in radians           */

    cairo_set_line_width (cr, 10.0);
    cairo_arc (cr, xc, yc, radius, angle1, angle2);
    cairo_stroke (cr);

/* draw helping lines */
    cairo_set_source_rgba (cr, 1, 0.2, 0.2, 0.6);
    cairo_set_line_width (cr, 6.0);

    cairo_arc (cr, xc, yc, 10.0, 0, 2*M_PI);
    cairo_fill (cr);

    cairo_arc (cr, xc, yc, radius, angle1, angle1);
    cairo_line_to (cr, xc, yc);
    cairo_arc (cr, xc, yc, radius, angle2, angle2);
    cairo_line_to (cr, xc, yc);
    cairo_stroke (cr);

    cairo_show_page(cr);
    cairo_destroy(cr);
}

まだ描画についてよくわかっていないので、これから把握していきたいと思います。

最後の編集者: YIS (2009-04-21 08:05:01)

オフライン

 

#10 2009-04-22 09:20:59

YIS
メンバ
登録日: 2009-03-29

Re: [解決済]C言語で点や線を描画するにはどうすれば?

皆さんおはようございます。昨日から移植開始し今日完了しました。まだ色表現など納得がいかないところもありますが、ひとまず完了としたいと思います。

いろいろご助言いただいた皆さん、フォーラムの方、そしてインターネットで画像描画を解説していただいているサイトさん、ありがとうございます。皆さんのお力がなければ、一人でここまではできなかったと思います。本当にありがとうございます。:)

備忘録にコードを書き込みます。

コード:

// 「Xlib Programming Lectures」さんのサイトを参考にさせていただいてます。ありがとうございます!!^^
// コンパイル gcc -lm $(pkg-config --cflags --libs cairo) hello.c
// 移植始めます。(2009/04/21)
// 暫定的移植完了(2009/04/22)

#include<stdio.h>
#include<stdlib.h>        // exit()関数用
#include<math.h>        // M_PI,sqrt()に必要
#include <cairo.h>
#include <cairo-xlib.h>


#define WIN_W     600  /* ウィンドウの幅   */
#define WIN_H     400  /* ウィンドウの高さ */
#define WIN_X     0.0  /* ウィンドウ表示位置(X) */
#define WIN_Y     0.0  /* ウィンドウ表示位置(Y) */
#define BORDER    1   /* ボーダの幅      */

// 光源の位置(x,y,z)
static double kox = 7.0, koy = 7.0, koz = 14.0;

static int hougan = 20;        // 拡大定数
static int xplus=WIN_W/2,yplus=WIN_H/2;    // (x,y)軸
static double min=0,max=0;        // cos(θ)の最小値と最大値を格納

// draw()関数のプロトタイプ宣言
static void draw( cairo_surface_t *surface );

//DrawPixel()関数のプロトタイプ宣言
static DrawPixel(double x, double y, double kosain, cairo_t *cr);


int 
main( void )
{
    Display*    dpy;         /* ディスプレイ */
    Window        root;        /* ルートウィンドウ */
    Window        win;         /* 表示するウィンドウ */
    int            screen;      /* スクリーン */
    unsigned long  black,white; /* 黒と白のピクセル値 */
    GC            gc;          /* グラフィックスコンテキスト */
    XEvent        evt;         /* イベント構造体 */

    Colormap    cmap;        /* カラーマップ */
    XColor        color, exact;
    cairo_surface_t *surface;        //cairoの構造体の中のひとつ!?


    /* Xサーバと接続する */
    dpy = XOpenDisplay( "" );
    if (dpy == NULL) {
        printf("Disply がオープンできません\n");
        exit(1);
    }

    /* ディスプレイ変数の取得 */
    root   = DefaultRootWindow( dpy );    // デフォルト・ウィンドウ!?
    screen = DefaultScreen( dpy );        // デフォルト・スクリーン!?

    /* XAllocNamedColor() のためにカラーマップを取得 */
    cmap   = DefaultColormap( dpy, screen ); 

    /* 白、黒のピクセル値を取得 */
    white  = WhitePixel( dpy, screen );
    black  = BlackPixel( dpy, screen );

    /* ウィンドウを作成する。この時点ではまだ画面に表示されない。*/
    win = XCreateSimpleWindow( dpy, root,
           WIN_X, WIN_Y, WIN_W, WIN_H, BORDER, black, white);

    /* グラフィックスコンテキストを作る */
    gc = XCreateGC( dpy, win, 0, NULL );

    /* Xサーバから通知してもらうイベントを指定
       ここではキー押下イベントの他に Expose イベントを選択している */
    XSelectInput( dpy, win, KeyPressMask | ExposureMask );

    /* ウィンドウを画面に表示する(マップする)。 */
    XMapWindow( dpy, win );

    // ウィンドウのタイトル
    XStoreName(dpy, win, "draw sphere with Cairo");

    // <特定の作画可能に引き込まれるXlibの表面を作成します。 色が作画可能に表される方法は提供による視覚で指定されます。>
// らしいです。^^;
    surface=cairo_xlib_surface_create(dpy, win, DefaultVisual(dpy, 0), WIN_W, WIN_H);


/* Xサーバからイベントを読み込んで随時処理していくイベントループ */
    while(1) {

        XNextEvent( dpy, &evt );

        // イベント判定(キー入力で終了)
        switch( evt.type ) {
                case Expose:      
                    if ( evt.xexpose.count == 0 ) {
                        draw( surface );
                    }
                    break;

                case KeyPress:
                    // cairoリソースの解放
                    cairo_surface_destroy(surface);

                    // X-Window リソース解放
                    XFreeGC( dpy, gc );
                    XDestroyWindow( dpy, win );
                    XCloseDisplay( dpy );
                    printf("MAX = %14.11f , MIN = %14.11f\n",max,min);
                    return 0;
        } // switch判定終了
    } // whileループ
}    //main()の終わり



// 描画ルーチン
static void
draw( cairo_surface_t *surface )
{
//Basic to Cairo スタート
    int i;
    double r=5.0;        //球の半径
    double kstep=0.07;
    double x,y,z,dumy;
    double kosain;
    double A,B,C;

// ここからcairoでの描画です
    cairo_t *cr;
    cr = cairo_create (surface);
// 方眼紙描画
    cairo_set_source_rgb(cr, 0.3, 0.3, 0.0);
    cairo_set_line_width (cr, 1.0);

    for (i=WIN_X ; i<WIN_W; i+=hougan) {
        cairo_move_to (cr, i, WIN_Y);
        cairo_line_to (cr, i, WIN_H);
        cairo_stroke (cr);
    }
    for (i=WIN_Y ; i<WIN_H; i+=hougan) {
        cairo_move_to (cr, WIN_X, i);
        cairo_line_to (cr, WIN_W, i);
        cairo_stroke (cr);
    }

// (x,y) 座標軸を描く
    cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
// X軸
    cairo_move_to (cr, WIN_X, WIN_H-yplus);
    cairo_line_to (cr, WIN_W, WIN_H-yplus);
    cairo_stroke (cr);
// Y軸
    cairo_move_to (cr, WIN_X+xplus, WIN_Y);
    cairo_line_to (cr, WIN_X+xplus, WIN_H);
    cairo_stroke (cr);

// 光源のおおよその位置(Z軸は考慮していない)
    cairo_set_source_rgb(cr, 0.9, 0.7, 0.0);
    cairo_arc (cr, kox*hougan+xplus, WIN_H-koy*hougan-yplus, 3, 0, 2 * M_PI);
    cairo_fill (cr);

    cairo_show_page(cr);

// メインルーチン
    // 座標(x,y,z)が球表面かどうか調べる
    for ( z=0 ; z <= r ; z+=kstep ) {    //zの値を変化させていく(zループ)
        for ( x=-r ; x <= r ; x+=kstep ) {    //xの値を変化させていく(xループ)

            dumy=sqrt( r*r - x*x -z*z );    // yの値を求める(符号にプラス・マイナスが存在する)

            y=dumy;
            // 光源との角度(θ)を求める
            A=x*(x-kox)+y*(y-koy)+z*(z-koz);
            B=sqrt(x*x+y*y+z*z);
            C=sqrt((x-kox)*(x-kox)+(y-koy)*(y-koy)+(z-koz)*(z-koz));
            if (B*C!=0) {
                kosain=A/(B*C);
                DrawPixel(x,y,kosain, cr);
            }
            // cos(θ)の現在までの最大値と最小値を代入する
            if (kosain<min) min=kosain;
            if (kosain>max) max=kosain;

            y=-dumy;
            // 光源との角度(θ)を求める
            A=x*(x-kox)+y*(y-koy)+z*(z-koz);
            B=sqrt(x*x+y*y+z*z);
            C=sqrt((x-kox)*(x-kox)+(y-koy)*(y-koy)+(z-koz)*(z-koz));
            if (B*C!=0) {
                kosain=A/(B*C);
                DrawPixel(x,y,kosain, cr);
            }
            // cos(θ)の現在までの最大値と最小値を代入する
            if (kosain<min) min=kosain;
            if (kosain>max) max=kosain;

        } // xループ終了
        cairo_show_page(cr);
    } // zループ終了
    cairo_show_page(cr);
    cairo_destroy(cr);
}    // メインルーチン終了


// ビクセル描画関数
static
DrawPixel(double x, double y, double kosain, cairo_t *cr)
{
    if (kosain>0) cairo_set_source_rgb(cr, 0.1, 0.1, 0.1);
    if (kosain <= 0) cairo_set_source_rgb(cr, 0.0, 0.0, -kosain);    // 初期値に戻しました^^;

    cairo_move_to (cr, x*hougan + xplus+1.0, WIN_H - y*hougan - yplus+1.0);
    cairo_line_to (cr, x*hougan + xplus, WIN_H - y*hougan - yplus);
    cairo_stroke (cr);
    return 0;
}

新版ubuntuまでもう少しですね。スタッフの皆さん頑張ってください。:)

必要の無い前回の変数などが入っていましたので少し修正しました。
コメントも追加していますので、興味のある方は見てください。:)

C言語初心者ですので、暖かい目で見ていただくと助かります。^^;

最後の編集者: YIS (2009-04-22 17:45:06)

オフライン

 

#11 2009-04-22 15:34:58

okamrua
メンバ
From: 福岡
登録日: 2008-07-11

Re: [解決済]C言語で点や線を描画するにはどうすれば?

こんにちは。
しばらく様子見してましたが、上手くいった様子で何よりです。

というわけで、散々煽った手前、きちんとコンパイルして動作確認しておきました。
結果は・・・・・グッジョブ!です :D

今後の活躍に期待してますね。(またもプレッシャー(笑))

オフライン

 

#12 2009-04-22 17:55:51

YIS
メンバ
登録日: 2009-03-29

Re: [解決済]C言語で点や線を描画するにはどうすれば?

こんちはokamruaさん。
いろいろ、お教えいただき感謝しています。:)

コンパイルありがとうございます。3Dの座標変換を会得したら、また球作りに挑戦しようと思います。^^;

プレッシャー・・・。(笑)が、頑張ります!:)

実はまだ調べてないですが、OpenGL?の方も視野に入っているかもしれません。うろ覚えですがCADなどに使われているという話を聞いたことがあるような気もします・・・?

しかしまず基本からです!2Dの座標変換を学習します!

最後の編集者: YIS (2009-04-22 20:02:08)

オフライン

 

#13 2009-07-14 16:57:38

YIS
メンバ
登録日: 2009-03-29

Re: [解決済]C言語で点や線を描画するにはどうすれば?

こんにちは、YISです。最後の投稿から随分と日が経ちました・・・。フォーラムはたまに拝見させていただいていました。しかし、バグがなかなかとれず半ば放置気味にしたのも事実です。

ここ最近の話ですが、急な進展があり球の改良版がなんとか皆さんにお見せできるようになったかと思います。

コメントにも書いていますが、科学技術計算用ではないので趣味のC言語と思ってください。

今はopenGLについて調べています(または学習)。なのでcairoでの描画は今回で最後の投稿となるかもしれません。

openGLの話になりますが、インターネット上で散々検索しましたがなかなか初歩的なサンプルソースを置いているサイトさんが無く、今日は、ほぼ検索だけに終わった感があります。書籍を購入しないと前に進みにくい感がありました。あるサイトさんを発見して順調に進み始めました。これからお世話になるかと思います。よろしくお願いします。

では最後に球のソースコードを置いておきます。座標軸描画などの部分は、アスキー・ラーニングシステム 1.入門コース の 入門グラフィックス から借用しています。ありがとうございます。少しでも座標描画などを近づけようとした痕跡となっています。敬意をこめてアップします。問題があるようでしたら言ってください、描画部分を変更しようと思います。

コード:

// 多数のサイトさんを参考にさせていただいています。ありがとうございます^^
// また、ubuntuコミュニティーの方々もありがとうございます。^^

// (2009/07/12)現在の目標は「入門グラフィックス(ASCII)」と、
// 私のオリジナルの球プログラムの座標系を統一することです
// (2009/07/14)統一あきらめました(><

// コンパイル方法
// gcc $(pkg-config --cflags --libs cairo) hello.c
// hello.c のところは読み替えてください

// 画面に球体が表示されればokです。
// 終了は、すべてのグラフィックの描画後、
//「キーボードのいずれかのキー」を押してください。

// 3D座標変換過去履歴(別プログラム)
// (2009/04/23)より作成開始
// (2009/05/02)画像出力暫定的完成(Z軸は考慮されています)
// (2009/05/19)平行移動の部分で苦戦しています^^;
// (2009/06/11)活動再開しましたが、やはり平行移動に手間取っています
// (2009/07/09)しばらくこのプログラムから遠ざかっていましたが、
// 復帰しました。なかなかバグがとれないです・・・。(苦笑)
// (2009/07/09)バグがとれました!!Z軸まわりの回転移動に進みます!(嬉)
// (2009/07/09)回転終了。続いて2Dクリッピングにとりかかります
// (2009/07/12)2Dクリッピングは程々にして、3Dクリッピングに入ります
// しかし挫折^^;

// 球作成関係過去履歴(このプログラム)
// (2009/04/21)移植始めます。
// (2009/04/22)暫定的移植完了
// (2009/07/08)少し手を加えました
// (2009/07/12)改良を始めます(一旦手動でマージ)
// (2009/07/12)マージ完了。座標を統一するのは明日以降です
// (2009/07/13)マージ時の不具合解消を目指します
// (2009/07/13)ほぼ解消。Zループを変更します(苦戦中)
// (2009/07/13)Zループ変更しました
// (2009/07/13)球の平行移動に挑戦
// (2009/07/14)XとYの移動はできますが、Z軸の移動ができませんでした(挫折)
// (2009/07/14)一応改良版の完成とします
// (2009/07/14)フォラームへのアップ用にコメント追加しました
// (2009/07/14)このプログラムの変数をいじる場合、
// 科学技術計算用ではないので、あまり大胆に変更しない方が
// 良いかもしれません^^; 最初は半径をいじるくらいからどうぞ^^;
// (2009/07/14)openGLの学習を始めました!
// [GLUTによる「手抜き」OpenGL入門]さん、他のサイトさん
// よろしくお願いします!^^


#include<stdio.h>
#include<stdlib.h>        // exit()関数用
#include<math.h>        // 三角関数,M_PI,sqrt()に必要
#include <cairo.h>
#include <cairo-xlib.h>


#define WIN_W     600    /* ウィンドウの幅 */
#define WIN_H     400    /* ウィンドウの高さ */
#define WIN_X     0.0    /* ウィンドウ表示位置(X) */
#define WIN_Y     0.0    /* ウィンドウ表示位置(Y) */
#define BORDER    1        /* ボーダの幅 */

// 座標中心の(x,y)
double xo,yo;

// クリッピング領域(2Dクリップです^^;)
double clgosa = 2.0;     // 枠の太さ
// クリップ範囲の(x,y)
double cx1=150,cy1=100,cx2=WIN_W-150,cy2=WIN_H-100;

double kox = 50.0, koy = 60.0, koz = 110.0;    // 光源の位置(x,y,z)

int hougan;                // 拡大定数
int xplus,yplus;        // (x,y)軸
double min=0,max=0;        // cos(θ)の最小値と最大値を格納


// draw()関数のプロトタイプ宣言
// 描画のメイン関数です
int draw( cairo_surface_t *surface );

// DrawLine()のプロトタイプ宣言
// 直線をひく関数です
int DrawLine( double, double, double, double , cairo_t *cr );

// clipping()のプロトタイプ宣言
// 2Dクリッピングの関数です
int clipping( double, double );

// DrawPixel()のプロトタイプ宣言
// ピクセル描画関数(のつもり)です
int DrawPixel( double, double, double, cairo_t *cr );


// メイン関数の始まりです
int
main()
{
    // 変数の宣言
    Display        *dpy;        /* ディスプレイ */
    Window        root_win;    /* ルートウィンドウ */
    Window        win;        /* 表示すeるウィンドウ */
    int            screen;        /* スクリーン */
    unsigned long black,white;    /* 黒と白のピクセル値 */
    GC            gc;            /* グラフィックスコンテキスト */
    XEvent        evt;        /* イベント構造体 */
    cairo_surface_t    *surface; // cairoの構造体の中のひとつ!?


    /* Xサーバと接続する */
    dpy = XOpenDisplay( NULL );
    if (dpy == NULL) {
        printf("Disply がオープンできません\n");
        exit(1);
    }

    /* ディスプレイ変数の取得 */
    root_win = DefaultRootWindow( dpy ); // デフォルト・ウィンドウ!?
    screen = DefaultScreen( dpy );        // デフォルト・スクリーン!?

    /* 白、黒のピクセル値を取得 */
    white = WhitePixel( dpy, screen );
    black = BlackPixel( dpy, screen );

    /* ウィンドウを作成する。この時点ではまだ画面に表示されない。*/
    win = XCreateSimpleWindow( dpy, root_win,WIN_X, WIN_Y,
                             WIN_W, WIN_H, BORDER, white, black);

    /* グラフィックスコンテキストを作る */
    gc = XCreateGC( dpy, win, 0, NULL );

    /* Xサーバから通知してもらうイベントを指定 */
    XSelectInput( dpy, win, KeyPressMask | ExposureMask );

    /* ウィンドウを画面に表示する(マップする)。*/
    XMapWindow( dpy, win );
    XFlush( dpy );

    // ウィンドウのタイトル
    XStoreName(dpy, win, "draw sphere with Cairo");

    // cairoの初期処理!?
    surface=cairo_xlib_surface_create(dpy, win,
             DefaultVisual(dpy, 0), WIN_W, WIN_H);

/* Xサーバからイベントを読み込んで随時処理していくイベントループ */
    while(1) {
        XNextEvent( dpy, &evt );
        // イベント判定(キー入力で終了)
        switch( evt.type ) {
            case Expose:
                if ( evt.xexpose.count == 0 ) {
                    draw( surface );
                }
                break;

            case KeyPress:
                // cairoリソース?の解放
                cairo_surface_destroy(surface);

                // X-Window リソースの解放
                XFreeGC( dpy, gc );
                XDestroyWindow( dpy , win ); // ウィンドウの消滅
                XCloseDisplay( dpy );         // X-Windowとの接続解除
                printf("MAX = %f , MIN = %f\n",max,min);
                return 0;
        } // switch文終了

    } // whileループ

} //main()の終わり



// 描画のメインルーチン    draw()関数
int
draw( cairo_surface_t *surface )
{
    int i;            // ループのカウント用一般変数
    double sx,sy;    // x方向とy方向のメモリを描画するときに使用する
    double nx,ny;
    double bx;
    double cxy;
    double b1,b2,b3,b4,b5,b6;
    double sx1,sx2,sy1,sy2;

// (2009/07/12)クリッピングについては未完です
/*    double h=20;    // 前方クリッピング面(スクリーン)までの距離
    double f=100;    // 後方クリピング面までの距離
    double k=10;    // 投影面(スクリーン)の横の大きさの1/2
    double sa = k/h;    // 視野角度の正接
*/

    double r;            // 半径の計算に使います
    double kx,ky,kz;    // (x,y,z)座標[方眼用データです]
    double kosain;        // COS(θ)です。反射角度による輝度に使っています
    double A,B,C;        // 反射角度演算用の収納変数です
    int WriteFlag;        // 2Dクリッピング用のフラグです
    double hankei=3.0, dr=1.0;    // 球の半径と増減値です
    double j,k,m;

    nx=WIN_W-1;            // 仮想スクリーンの横ドット数
    ny=WIN_H-1;            // 仮想スクリーンの縦ドット数
    bx=20.0;            // スクリーンの目盛数
    cxy=1.017;            // モニタに依存する縦横比!?

// cairoの設定
    cairo_t *cr;
    cr = cairo_create (surface);
    cairo_set_line_width (cr, 1.0);
    cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);

// 座標メモリを描く
    xo=.5*nx;yo=.5*ny;    // 座標中心の位置

    hougan = nx/bx-1;    // 方眼紙1メモリのドット数です
    xplus = xo; yplus = yo;    // (x,y)軸です

// アスキー本の変数
    b1=nx/bx-1;
    b2=b1/cxy;
    b3=b1*bx/2;
    b4=(ny/b2/2)*b2;

// x方向のメモリを描く
    for ( i=0 ; i<=bx ; i++ ) {
        b5=xo-b3+b1*i;
        for ( j=yo-b4 ; j<=yo+b4 ; j+=nx/120/cxy ) {
            sx=b5;sy=j;
            WriteFlag = clipping(sx,sy);
            if (WriteFlag == 1) {
                cairo_move_to (cr, sx, sy);    
                cairo_line_to (cr, sx, sy+1);
            }
        }
    }


// y方向のメモリを描く
    for ( i=0 ; i<=(ny/2) ; i++ ) {
        b6=yo-b4+b2*i;
        for ( j=xo-b3 ; j<=xo+b3 ; j+=nx/120 ) {
            sx=j;sy=b6;
            WriteFlag = clipping(sx,sy);
            if (WriteFlag == 1) {
                cairo_move_to (cr, sx, sy);    
                cairo_line_to (cr, sx, sy+1);
            }
        }
    }

// (x,y)軸を描く
    sx1=xo;sy1=cy1;sx2=xo;sy2=cy2;
    DrawLine(sx1,sy1,sx2,sy2,cr);
    sx1=cx1;sy1=yo;sx2=cx2;sy2=yo;
    DrawLine(sx1,sy1,sx2,sy2,cr);


// 2Dクリッピング領域の外周を描く
// こうしないと枠線の上に球を描画してしまう
    cairo_set_line_width (cr, clgosa);

    cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
    DrawLine(cx1-clgosa,cy1,cx1-clgosa,cy2,cr);
    DrawLine(cx2+clgosa,cy1,cx2+clgosa,cy2,cr);
    DrawLine(cx1,cy1-clgosa,cx2,cy1-clgosa,cr);
    DrawLine(cx1,cy2+clgosa,cx2,cy2+clgosa,cr);
    cairo_stroke (cr);

//-------------------------------------------- ここからループ
// 初期設定はループ回数を1回にしています

    while( hankei >= 3.0 ) {

// 球表示部分
        cairo_set_line_width (cr, 1.0);
        m=0.0570/hankei;    // 円周の当分数!?です

        for ( k = M_PI ; k >= 0 ; k += -m ) {
            kz = hankei*cos(k);        // zの値
            r  = hankei*sin(k);
            for ( j=0 ; j <= M_PI*2 ; j += m ) {
                kx=r*cos(j);        // xの値
                ky=r*sin(j);        // yの値

                // 光源との角度を求めます
                A=kx*(kx-kox)+ky*(ky-koy)+kz*(kz-koz);
                B=sqrt(kx*kx+ky*ky+kz*kz);
                C=sqrt((kx-kox)*(kx-kox)+(ky-koy)*
                    (ky-koy)+(kz-koz)*(kz-koz));
                if ((B*C) !=0) {
                    kosain=A/(B*C);
                    WriteFlag = DrawPixel(kx,ky,kosain,cr);
                    cairo_stroke (cr);

                    // COS(θ)の最小値と最大値を格納
                    if (kosain<min) min=kosain;
                    if (kosain>max) max=kosain;
                }
            }
        }
        printf("hankei = %f\n",hankei);
        hankei = hankei - dr;
    } // whileループ終了
//-------------------------------------------- ループここまで

    cairo_destroy(cr);

    return 0;
} // 描画ルーチン    draw()関数 終了


// 線の描画関数
int
DrawLine(double x1, double y1, double x2, double y2, cairo_t *cr )
{
    cairo_move_to (cr, x1, y1);
    cairo_line_to (cr, x2, y2);

    return 0;
}



// 2Dクリッピング関数(これで勘弁してください^^;)
int
clipping(double x, double y)
{
    int flag = 0;
    if ( (x>cx1) && (cx2>x)    && (y<cy2) && (cy1<y) ) {
        flag = 1;
    }

    return flag;
}



// ビクセル描画関数
int
DrawPixel(double x, double y, double kosain, cairo_t *cr)
{
    double pixelwidth = 2.2;
    int flag;

    flag = clipping(x*hougan + xplus,WIN_H - y*hougan - yplus);
    if (flag == 0) return -1;

    // (2009/07/08)環境光を追加してみます。作りかけです・・・。
    // (2009/07/13)一応これでokかな?と判断しました^^;
    double R,G,B;

    R = 0;
    G = -kosain*0.8+0.2;
    B = G;

    cairo_set_source_rgb(cr,R,G,B);
//    if (kosain>0) cairo_set_source_rgb(cr,R,G,B);
//    if (kosain<=0) cairo_set_source_rgb(cr,R,G,B);

    cairo_move_to (cr, x*hougan + xplus + pixelwidth,
                     WIN_H - y*hougan - yplus - pixelwidth);
    cairo_line_to (cr, x*hougan + xplus, WIN_H - y*hougan - yplus);

    return 0;
}

オフライン

 

#14 2009-07-15 08:02:33

YIS
メンバ
登録日: 2009-03-29

Re: [解決済]C言語で点や線を描画するにはどうすれば?

すみません、昨日アップしたソースコードにバグがありました。

C言語がわかる方なら修正は簡単と思いますが、一応修正版をアップしておきます。

https://forums.ubuntulinux.jp/viewtopic.php?pid=33413
この書き込みを、さきほど発見しました。

またバグがあったら、またアップですね・・・。

コード:

// 多数のサイトさんを参考にさせていただいています。ありがとうございます^^
// また、ubuntuコミュニティーの方々もありがとうございます。^^

// (2009/07/12)現在の目標は「入門グラフィックス(ASCII)」と、
// 私のオリジナルの球プログラムの座標系を統一することです
// (2009/07/14)統一あきらめました(><

// コンパイル方法
// gcc $(pkg-config --cflags --libs cairo) hello.c
// hello.c のところは読み替えてください

// 画面に球体が表示されればokです。
// 終了は、すべてのグラフィックの描画後、
//「キーボードのいずれかのキー」を押してください。

// 3D座標変換過去履歴(別プログラム)
// (2009/04/23)より作成開始
// (2009/05/02)画像出力暫定的完成(Z軸は考慮されています)
// (2009/05/19)平行移動の部分で苦戦しています^^;
// (2009/06/11)活動再開しましたが、やはり平行移動に手間取っています
// (2009/07/09)しばらくこのプログラムから遠ざかっていましたが、
// 復帰しました。なかなかバグがとれないです・・・。(苦笑)
// (2009/07/09)バグがとれました!!Z軸まわりの回転移動に進みます!(嬉)
// (2009/07/09)回転終了。続いて2Dクリッピングにとりかかります
// (2009/07/12)2Dクリッピングは程々にして、3Dクリッピングに入ります
// しかし挫折^^;

// 球作成関係過去履歴(このプログラム)
// (2009/04/21)移植始めます。
// (2009/04/22)暫定的移植完了
// (2009/07/08)少し手を加えました
// (2009/07/12)改良を始めます(一旦手動でマージ)
// (2009/07/12)マージ完了。座標を統一するのは明日以降です
// (2009/07/13)マージ時の不具合解消を目指します
// (2009/07/13)ほぼ解消。Zループを変更します(苦戦中)
// (2009/07/13)Zループ変更しました
// (2009/07/13)球の平行移動に挑戦
// (2009/07/14)XとYの移動はできますが、Z軸の移動ができませんでした(挫折)
// (2009/07/14)一応改良版の完成とします
// (2009/07/14)フォラームへのアップ用にコメント追加しました
// (2009/07/14)このプログラムの変数をいじる場合、
// 科学技術計算用ではないので、あまり大胆に変更しない方が
// 良いかもしれません^^; 最初は半径をいじるくらいからどうぞ^^;
// (2009/07/14)openGLの学習を始めました!
// [GLUTによる「手抜き」OpenGL入門]さん、他のサイトさん
// よろしくお願いします!^^


#include<stdio.h>
#include<stdlib.h>        // exit()関数用
#include<math.h>        // 三角関数,M_PI,sqrt()に必要
#include <cairo.h>
#include <cairo-xlib.h>


#define WIN_W     600    /* ウィンドウの幅 */
#define WIN_H     400    /* ウィンドウの高さ */
#define WIN_X     0.0    /* ウィンドウ表示位置(X) */
#define WIN_Y     0.0    /* ウィンドウ表示位置(Y) */
#define BORDER    1        /* ボーダの幅 */

// 座標中心の(x,y)
double xo,yo;

// クリッピング領域(2Dクリップです^^;)
double clgosa = 2.0;     // 枠の太さ
// クリップ範囲の(x,y)
double cx1=150,cy1=100,cx2=WIN_W-150,cy2=WIN_H-100;

double kox = 50.0, koy = 60.0, koz = 110.0;    // 光源の位置(x,y,z)

int hougan;                // 拡大定数
int xplus,yplus;        // (x,y)軸
double min=0,max=0;        // cos(θ)の最小値と最大値を格納


// draw()関数のプロトタイプ宣言
// 描画のメイン関数です
int draw( cairo_surface_t *surface );

// DrawLine()のプロトタイプ宣言
// 直線をひく関数です
int DrawLine( double, double, double, double , cairo_t *cr );

// clipping()のプロトタイプ宣言
// 2Dクリッピングの関数です
int clipping( double, double );

// DrawPixel()のプロトタイプ宣言
// ピクセル描画関数(のつもり)です
int DrawPixel( double, double, double, cairo_t *cr );


// メイン関数の始まりです
int
main()
{
    // 変数の宣言
    Display        *dpy;        /* ディスプレイ */
    Window        root_win;    /* ルートウィンドウ */
    Window        win;        /* 表示すeるウィンドウ */
    int            screen;        /* スクリーン */
    unsigned long black,white;    /* 黒と白のピクセル値 */
    GC            gc;            /* グラフィックスコンテキスト */
    XEvent        evt;        /* イベント構造体 */
    cairo_surface_t    *surface; // cairoの構造体の中のひとつ!?


    /* Xサーバと接続する */
    dpy = XOpenDisplay( NULL );
    if (dpy == NULL) {
        printf("Disply がオープンできません\n");
        exit(1);
    }

    /* ディスプレイ変数の取得 */
    root_win = DefaultRootWindow( dpy ); // デフォルト・ウィンドウ!?
    screen = DefaultScreen( dpy );        // デフォルト・スクリーン!?

    /* 白、黒のピクセル値を取得 */
    white = WhitePixel( dpy, screen );
    black = BlackPixel( dpy, screen );

    /* ウィンドウを作成する。この時点ではまだ画面に表示されない。*/
    win = XCreateSimpleWindow( dpy, root_win,WIN_X, WIN_Y,
                             WIN_W, WIN_H, BORDER, white, black);

    /* グラフィックスコンテキストを作る */
    gc = XCreateGC( dpy, win, 0, NULL );

    /* Xサーバから通知してもらうイベントを指定 */
    XSelectInput( dpy, win, KeyPressMask | ExposureMask );

    /* ウィンドウを画面に表示する(マップする)。*/
    XMapWindow( dpy, win );
    XFlush( dpy );

    // ウィンドウのタイトル
    XStoreName(dpy, win, "draw sphere with Cairo");

    // cairoの初期処理!?
    surface=cairo_xlib_surface_create(dpy, win,
             DefaultVisual(dpy, 0), WIN_W, WIN_H);

/* Xサーバからイベントを読み込んで随時処理していくイベントループ */
    while(1) {
        XNextEvent( dpy, &evt );
        // イベント判定(キー入力で終了)
        switch( evt.type ) {
            case Expose:
                if ( evt.xexpose.count == 0 ) {
                    draw( surface );
                }
                break;

            case KeyPress:
                // cairoリソース?の解放
                cairo_surface_destroy(surface);

                // X-Window リソースの解放
                XFreeGC( dpy, gc );
                XDestroyWindow( dpy , win ); // ウィンドウの消滅
                XCloseDisplay( dpy );         // X-Windowとの接続解除
                printf("MAX = %f , MIN = %f\n",max,min);
                return 0;
        } // switch文終了

    } // whileループ

} //main()の終わり



// 描画のメインルーチン    draw()関数
int
draw( cairo_surface_t *surface )
{
    int i;            // ループのカウント用一般変数
    double sx,sy;    // x方向とy方向のメモリを描画するときに使用する
    double nx,ny;
    double bx;
    double cxy;
    double b1,b2,b3,b4,b5,b6;
    double sx1,sx2,sy1,sy2;

// (2009/07/12)クリッピングについては未完です
/*    double h=20;    // 前方クリッピング面(スクリーン)までの距離
    double f=100;    // 後方クリピング面までの距離
    double k=10;    // 投影面(スクリーン)の横の大きさの1/2
    double sa = k/h;    // 視野角度の正接
*/

    double r;            // 半径の計算に使います
    double kx,ky,kz;    // (x,y,z)座標[方眼用データです]
    double kosain;        // COS(θ)です。反射角度による輝度に使っています
    double A,B,C;        // 反射角度演算用の収納変数です
    int WriteFlag;        // 2Dクリッピング用のフラグです
    double hankei=3.0, dr=1.0;    // 球の半径と増減値です
    int loopcnt=1;
    double j,k,m;

    nx=WIN_W-1;            // 仮想スクリーンの横ドット数
    ny=WIN_H-1;            // 仮想スクリーンの縦ドット数
    bx=20.0;            // スクリーンの目盛数
    cxy=1.017;            // モニタに依存する縦横比!?

// cairoの設定
    cairo_t *cr;
    cr = cairo_create (surface);
    cairo_set_line_width (cr, 1.0);
    cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);

// 座標メモリを描く
    xo=.5*nx;yo=.5*ny;    // 座標中心の位置

    hougan = nx/bx-1;    // 方眼紙1メモリのドット数です
    xplus = xo; yplus = yo;    // (x,y)軸です

// アスキー本の変数
    b1=nx/bx-1;
    b2=b1/cxy;
    b3=b1*bx/2;
    b4=(ny/b2/2)*b2;

// x方向のメモリを描く
    for ( i=0 ; i<=bx ; i++ ) {
        b5=xo-b3+b1*i;
        for ( j=yo-b4 ; j<=yo+b4 ; j+=nx/120/cxy ) {
            sx=b5;sy=j;
            WriteFlag = clipping(sx,sy);
            if (WriteFlag == 1) {
                cairo_move_to (cr, sx, sy);    
                cairo_line_to (cr, sx, sy+1);
            }
        }
    }


// y方向のメモリを描く
    for ( i=0 ; i<=(ny/2) ; i++ ) {
        b6=yo-b4+b2*i;
        for ( j=xo-b3 ; j<=xo+b3 ; j+=nx/120 ) {
            sx=j;sy=b6;
            WriteFlag = clipping(sx,sy);
            if (WriteFlag == 1) {
                cairo_move_to (cr, sx, sy);    
                cairo_line_to (cr, sx, sy+1);
            }
        }
    }

// (x,y)軸を描く
    sx1=xo;sy1=cy1;sx2=xo;sy2=cy2;
    DrawLine(sx1,sy1,sx2,sy2,cr);
    sx1=cx1;sy1=yo;sx2=cx2;sy2=yo;
    DrawLine(sx1,sy1,sx2,sy2,cr);


// 2Dクリッピング領域の外周を描く
// こうしないと枠線の上に球を描画してしまう
    cairo_set_line_width (cr, clgosa);

    cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
    DrawLine(cx1-clgosa,cy1,cx1-clgosa,cy2,cr);
    DrawLine(cx2+clgosa,cy1,cx2+clgosa,cy2,cr);
    DrawLine(cx1,cy1-clgosa,cx2,cy1-clgosa,cr);
    DrawLine(cx1,cy2+clgosa,cx2,cy2+clgosa,cr);
    cairo_stroke (cr);

//-------------------------------------------- ここからループ
// 初期設定はループ回数を1回にしています

    while( loopcnt < 2  ) {

// 球表示部分
        cairo_set_line_width (cr, 1.0);
        m=0.0570/hankei;    // 円周の当分数!?です

        for ( k = M_PI ; k >= 0 ; k += -m ) {
            kz = hankei*cos(k);        // zの値
            r  = hankei*sin(k);
            for ( j=0 ; j <= M_PI*2 ; j += m ) {
                kx=r*cos(j);        // xの値
                ky=r*sin(j);        // yの値

                // 光源との角度を求めます
                A=kx*(kx-kox)+ky*(ky-koy)+kz*(kz-koz);
                B=sqrt(kx*kx+ky*ky+kz*kz);
                C=sqrt((kx-kox)*(kx-kox)+(ky-koy)*
                    (ky-koy)+(kz-koz)*(kz-koz));
                if ((B*C) !=0) {
                    kosain=A/(B*C);
                    WriteFlag = DrawPixel(kx,ky,kosain,cr);
                    cairo_stroke (cr);

                    // COS(θ)の最小値と最大値を格納
                    if (kosain<min) min=kosain;
                    if (kosain>max) max=kosain;
                }
            }
        }
        loopcnt+=1;
        printf("hankei = %f\n",hankei);
        hankei = hankei - dr;
    } // whileループ終了
//-------------------------------------------- ループここまで

    cairo_destroy(cr);

    return 0;
} // 描画ルーチン    draw()関数 終了


// 線の描画関数
int
DrawLine(double x1, double y1, double x2, double y2, cairo_t *cr )
{
    cairo_move_to (cr, x1, y1);
    cairo_line_to (cr, x2, y2);

    return 0;
}



// 2Dクリッピング関数(これで勘弁してください^^;)
int
clipping(double x, double y)
{
    int flag = 0;
    if ( (x>cx1) && (cx2>x)    && (y<cy2) && (cy1<y) ) {
        flag = 1;
    }

    return flag;
}



// ビクセル描画関数
int
DrawPixel(double x, double y, double kosain, cairo_t *cr)
{
    double pixelwidth = 2.2;
    int flag;

    flag = clipping(x*hougan + xplus,WIN_H - y*hougan - yplus);
    if (flag == 0) return -1;

    // (2009/07/08)環境光を追加してみます。作りかけです・・・。
    // (2009/07/13)一応これでokかな?と判断しました^^;
    double R,G,B;

    R = 0;
    G = -kosain*0.8+0.2;
    B = G;

    cairo_set_source_rgb(cr,R,G,B);
//    if (kosain>0) cairo_set_source_rgb(cr,R,G,B);
//    if (kosain<=0) cairo_set_source_rgb(cr,R,G,B);

    cairo_move_to (cr, x*hougan + xplus + pixelwidth,
                     WIN_H - y*hougan - yplus - pixelwidth);
    cairo_line_to (cr, x*hougan + xplus, WIN_H - y*hougan - yplus);

    return 0;
}

今日の朝チェックしといてよかった・・・。(笑)

オフライン

 

#15 2010-07-02 16:47:20

YIS
メンバ
登録日: 2009-03-29

Re: [解決済]C言語で点や線を描画するにはどうすれば?

こんにちは、超久しぶりの投稿となります。

しばらくフォーラムを離れていましたが、アカウント関連の出来事で、またフォーラムを見るようになりました。そして気づきました。

昔はあの状態が精一杯だった球表示プログラムですが、バグがあったり、「ここは、こうした方が良いな」と思う部分があります。

なので少し修正してみました。

hitoさん、okamruaさん、昔はたいへんお世話になりました。okamruaさんにいたっては名前を間違えた事もありました。(フォーラムのシステム的な変更で)修正ができなくってから気づきました。どうも、すみませんでした。

今日はお詫びの意味もこめて修正プログラムをつくってみました。

久しぶりの投稿で緊張気味ですが、頑張ってみます。

コード:

// コンパイル gcc $(pkg-config --cflags --libs cairo) kyuuHyouji14.c

#include<stdio.h>
#include<stdlib.h>    // exit()関数用
#include<math.h>    // M_PI,sqrt()に必要
#include <cairo.h>
#include <cairo-xlib.h>


#define WIN_W 600  /* ウィンドウの幅 */
#define WIN_H 400  /* ウィンドウの高さ */
#define WIN_X 0.0  /* ウィンドウ表示位置(X) */
#define WIN_Y 0.0  /* ウィンドウ表示位置(Y) */
#define BORDER 1   /* ボーダの幅 */


double kox = 7.0, koy = 7.0, koz = 14.0;    // 光源の位置(x,y,z)
int hougan = 20;    // 拡大定数
int xplus = WIN_W/2, yplus = WIN_H/2;    // (x,y)軸
double min = 0, max = 0;    // cos(θ)の最小値と最大値を格納
int ByougaFlag = 1;
int cx1 = 0, cx2 = WIN_W, cy1 = 0, cy2 = WIN_H;

//プロトタイプ宣言
void drawMain( cairo_surface_t *surface );
int DrawPixel(double, double, double, cairo_t *cr);
double KakudoKeisan(double x, double y, double z);
int clipping(int x, int y);
int houganByouga(cairo_t *cr);
int zahyoujikuByouga(cairo_t *cr);
int kougenByouga(cairo_t *cr);



int 
main(void)
{
    Display*    dpy;             /* ディスプレイ */
    Window        root;          /* ルートウィンドウ */
    Window        win;           /* 表示するウィンドウ */
    int            screen;      /* スクリーン */
    unsigned long  black,white;/* 黒と白のピクセル値 */
    GC            gc;            /* グラフィックスコンテキスト */
    XEvent        evt;           /* イベント構造体 */
    cairo_surface_t *surface;    //cairoの構造体の中のひとつ!?


    /* Xサーバと接続する */
    dpy = XOpenDisplay( "" );
    if (dpy == NULL) {
        printf("Disply がオープンできません\n");
        exit(1);
    }

    /* ディスプレイ変数の取得 */
    root   = DefaultRootWindow( dpy );    // デフォルト・ウィンドウ!?
    screen = DefaultScreen( dpy );        // デフォルト・スクリーン!?

    /* 白、黒のピクセル値を取得 */
    white  = WhitePixel( dpy, screen );
    black  = BlackPixel( dpy, screen );

    /* ウィンドウを作成する。この時点ではまだ画面に表示されない。*/
    win = XCreateSimpleWindow( dpy, root,
           WIN_X, WIN_Y, WIN_W, WIN_H, BORDER, black, white);

    /* グラフィックスコンテキストを作る */
    gc = XCreateGC( dpy, win, 0, NULL );

    /* Xサーバから通知してもらうイベントを指定
       ここではキー押下イベントの他に Expose イベントを選択している */
    XSelectInput( dpy, win, KeyPressMask | ExposureMask );

    /* ウィンドウを画面に表示する(マップする)。 */
    XMapWindow( dpy, win );

    // ウィンドウのタイトル
    XStoreName(dpy, win, "Kyuu no Byouga (Cairo)");

    // <特定の作画可能に引き込まれるXlibの表面を作成します。 色が作画可能に表される方法は提供による視覚で指定されます。>
    // 自動翻訳です(^^;
    surface = cairo_xlib_surface_create(dpy, win, DefaultVisual(dpy, 0), WIN_W, WIN_H);

    printf("描画終了後何かキーを押してください。プログラムを終了します。\n");
/* Xサーバからイベントを読み込んで随時処理していくイベントループ */
    while(1) {
        XNextEvent( dpy, &evt );
        switch( evt.type ) {        // イベント判定
                case Expose:      
                    if ( evt.xexpose.count == 0 ) {
                        if (ByougaFlag) {    //暫定的な対応処理(再描画はしません)
                            drawMain(surface);
                            ByougaFlag = 0;
                        }
                    }
                    break;

                case KeyPress:        //キー入力で終了
                    // cairoリソースの解放
                    cairo_surface_destroy(surface);

                    // X-Window リソース解放
                    XFreeGC( dpy, gc );
                    XDestroyWindow( dpy, win );
                    XCloseDisplay( dpy );
                    printf("MAX = %14.11f , MIN = %14.11f\n",max,min);
                    return 0;
        }
    }
}



//描画のメイン関数
void
drawMain( cairo_surface_t *surface )
{
    double r = 3.0;        //球の半径(0以上にしてください)
    double kstep = 0.05;

// ここからcairoでの描画です
    cairo_t *cr;
    cr = cairo_create (surface);

    houganByouga(cr);        // 方眼の目盛り描画
    zahyoujikuByouga(cr);    // (x,y) 座標軸を描く
    cairo_show_page(cr);

    double x,y,z;
    for (y = -r ; y <= r ; y += kstep) {
        for (x = -r ; x <= r ; x += kstep) {
            double kyuu = r*r - x*x - y*y;
            if (kyuu >= 0) {
                int cflag;
                cflag = clipping(x, y);        //2Dクリッピング
                if (cflag) {
                    double dumy;
                    dumy=sqrt(kyuu);

                    z = dumy;    //(z >= 0)の時に表示(カリング処理)
                    double kosain;
                    kosain = KakudoKeisan(x, y, z);    //cos(θ)の値を演算
                    //cos(θ)の値によって輝度を判定し描画する
                    if (kosain != -10) DrawPixel(x, y, kosain, cr);
                }
            }
        }
    }
    kougenByouga(cr);    // 光源のおおよその位置
    cairo_show_page(cr);
    cairo_destroy(cr);
}


// 描画関数(Cairo)
int
DrawPixel(double x, double y, double iro, cairo_t *cr)
{
    //表示色決定
    if (iro >= 0.0) {
        double R, G, B;
        R = 0.0;
        G = iro;
        B = iro;
        cairo_set_source_rgb(cr, R, G, B);
    } else {
        cairo_set_source_rgb(cr, 0, 0, 0);
    }

    //描画
    cairo_set_line_width (cr, 1.17);
    cairo_move_to (cr, x*hougan + xplus+1.0, WIN_H - (y*hougan + yplus+1.0));
    cairo_line_to (cr, x*hougan + xplus, WIN_H - (y*hougan + yplus));
    cairo_stroke (cr);
    return 0;
}


// 光源との角度cos(θ)を求める
double
KakudoKeisan(double x, double y, double z)
{
    double kosain;
    double A,B,C;

    A =x*kox + y*koy + z*koz;
    B =sqrt(x*x + y*y + z*z);
    C =sqrt(kox*kox + koy*koy + koz*koz);
    if (B*C != 0) {
        kosain = A/(B*C);
        // cos(θ)の現在までの最大値と最小値を代入する
        if (kosain < min) min = kosain;
        if (kosain > max) max = kosain;
        return kosain;
    } else {
        printf("cos(θ)計算不能\n");
        return -10;
    }
}


//2Dクリッピング関数
int
clipping(int x, int y)
{
    int d2cx = x*hougan + xplus;
    int d2cy = WIN_H - (y*hougan + yplus);

    if ((cx1 < d2cx)&&(cx2 > d2cx)&&(cy1 < d2cy)&&(cy2 > d2cy)) return 1;
    return 0;
}


//方眼目盛り描画関数
int
houganByouga(cairo_t *cr)
{
    cairo_set_line_width (cr, 0.2);
    cairo_set_source_rgb(cr, 0.7, 0.7, 0.0);
    int i;
    for (i = WIN_X ; i < WIN_W; i += hougan) {
        cairo_move_to (cr, i, WIN_Y);
        cairo_line_to (cr, i, WIN_H);
        cairo_stroke (cr);
    }
    for (i = WIN_Y ; i < WIN_H; i += hougan) {
        cairo_move_to (cr, WIN_X, i);
        cairo_line_to (cr, WIN_W, i);
        cairo_stroke (cr);
    }
    return 0;
}

//座標軸描画関数
int
zahyoujikuByouga(cairo_t *cr)
{
    cairo_set_line_width (cr, 1.0);
    cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);

    // X軸
    cairo_move_to (cr, WIN_X, WIN_H-yplus);
    cairo_line_to (cr, WIN_W, WIN_H-yplus);
    cairo_stroke (cr);

    // Y軸
    cairo_move_to (cr, WIN_X+xplus, WIN_Y);
    cairo_line_to (cr, WIN_X+xplus, WIN_H);
    cairo_stroke (cr);

    return 0;
}


//光源のおおよその位置描画
int
kougenByouga(cairo_t *cr)
{
    cairo_set_source_rgb(cr, 0.9, 0.7, 0.0);
    cairo_arc (cr, kox*hougan+xplus, WIN_H-koy*hougan-yplus, 10, 0, 2 * M_PI);
    cairo_fill (cr);

    return 0;
}

Yet Another Ruby Beginner」サイトさん、
X-Window Programming」サイトさん、
Xlib - Wikipedia」サイトさん、
Xlib Programming Lectures」サイトさん

より引用させていただいています。本当にありがとうございます。

追伸
バグなどあったらすみません。プログラムの投稿は多分最後になると思います。

オフライン

 

Board footer

Powered by FluxBB