2012年1月17日火曜日

数学関数のグラフ表示

今回は数学関数をX-WindowSystemでグラフ化する方法を載せたいと思います。
グラフ化することによって視覚的にわかり易くなり、実数解が存在するか程度ならすぐに分かります。

ではひとまず定義。



これが表示用の関数です。

ウィンドウの大きさは480*480で、うち上下左右40pxは空白部とします。
また、数値解析における分割数は100分割で、400px内を100分割して直線で結ぶ感じです。
つまり4pxは直線だけど大きい目で見たら曲線に見えるよね、って感じかな。

線を引くためには始点と終点が必要になりますが、終点は現在の計算点、始点は前回の計算点とします。
0→1、1→2、2→3点という風になります。

以下プログラムリスト。
Linuxの人はindentコマンドで整形するなりなんなりしてくだされ。

ちなみにindentコマンドは
sudo apt-get install indent
より
indent FILENAME -OPTION
で使えます。
OPTIONは-krをつかうと幸せ。

こんな感じになります。



以下リスト。


#include<stdio.h>
#include<stdlib.h>
#include<math.h>

#include<X11/Xlib.h>
#include<X11/Xutil.h>

#define X_MAX 400
#define Y_MAX 400

#define X_EDGE 40
#define Y_EDGE 40

#define I_MAX 100

void x_axis();
void y_axis();
void figure();
float func(float x);

int main(int argc,char **argv){
 Display *display;
 Window window;
 XEvent event;
 KeySym key;
 GC gc;
 char ch;
 
 display = XOpenDisplay(NULL);
 window = XCreateSimpleWindow(display,RootWindow(display,0),0,0,X_MAX + X_EDGE * 2,Y_MAX + Y_EDGE * 2,1,BlackPixel(display,0),WhitePixel(display,0));
 XSelectInput(display,window,ExposureMask | ButtonPressMask | KeyPressMask);
 XStoreName(display,window,argv[0]);
 XMapWindow(display,window);
 gc = DefaultGC(display,0);
 
 while(1){
  XNextEvent(display,&event);
  
  if(event.type == Expose){
   x_axis(display,window,gc);
   y_axis(display,window,gc);
   figure(display,window,gc);
  }
  
  if(event.type == ButtonPress){
   if(event.xbutton.button == Button3){
    XCloseDisplay(display);
    break;
   }
  }
  
  if(event.type == KeyPress){
   if(XLookupString(&event.xkey,&ch,1,&key,NULL) == True){
    if(ch == '\03'){
     XCloseDisplay(display);
     break;
    }
   }
  }
 }
}

void x_axis(Display *display,Window window,GC gc){
 int xtmp0,ytmp0,xtmp1,ytmp1;
 
 xtmp0 = X_EDGE;
 ytmp0 = Y_EDGE + Y_MAX / 2;
 xtmp1 = X_EDGE + X_MAX;
 ytmp1 = ytmp0;
 
 XDrawLine(display,window,gc,xtmp0,ytmp0,xtmp1,ytmp1);
}

void y_axis(Display *display,Window window,GC gc){
 int xtmp0,ytmp0,xtmp1,ytmp1;
 
 xtmp0 = X_EDGE + X_MAX / 2;
 ytmp0 = Y_EDGE;
 xtmp1 = xtmp0;
 ytmp1 = Y_EDGE + Y_MAX;
 
 XDrawLine(display,window,gc,xtmp0,ytmp0,xtmp1,ytmp1);
}

void figure(Display *display,Window window,GC gc){
 int i;
 float p_old,q_old,p_new,q_new;
 int x_old,y_old,x_new,y_new;
 int x_center,y_center;
 
 x_center = X_EDGE + X_MAX / 2;
 y_center = Y_EDGE + Y_MAX / 2;
 
 for(i = 0;i < I_MAX -1;i++){//
  p_old = - 5.0 + 10.0 * (float)i / (float)I_MAX;
  q_old = func(p_old);
  
  p_new = - 5.0 + 10.0 * (float)(i + 1) / (float)I_MAX;
  q_new = func(p_new);
  
  x_old = x_center + (int)(p_old * (float)X_MAX / 10.0);
  y_old = y_center - (int)(q_old * (float)Y_MAX / 10.0);
  
  x_new = x_center + (int)(p_new * (float)X_MAX / 10.0);
  y_new = y_center - (int)(q_new * (float)Y_MAX / 10.0);
  
  if((q_old > -5.0) && (q_old < 5.0) && (q_new > -5.0) && (q_new < 5.0)){
   XDrawLine(display,window,gc,x_old,y_old,x_new,y_new);
  }
 }
}

float func(float x){
 float value;
 
 value = 0.5 * x * x * x + 0.75 * x * x - 2.0 * x - 2.0;
 
 return value;
}

0 件のコメント:

コメントを投稿