/** @brief 2D & 3D グラフィックライブラリ @file graph.c @version 3.0 @author Fumi.Iseki (C) */ #include "graph.h" #include "jbxl_state.h" /** int get_idat(WSGraph gd, int xx, int yy, int zz) グラフィックデータ構造体 vpの任意の 1voxelの値(濃度)を返す.@n 座標の範囲チェックあり.Z軸の歪補整はなし. @param gd 操作対象となるグラフィックデータ構造体. @param xx,yy,zz 値を設定する xyz座標. @return (xx,yy,zz)点の濃度(輝度値).(xx,yy,zz)が座標の範囲外の場合は0を返す. */ int get_idat(WSGraph gd, int xx, int yy, int zz) { int ret = 0; if (xx>0&&yy>0&&zz>0&&xx=0&&ix=0&&iy=0&&iz0&&yy>0&&zz>0&&xx=0&&ix=0&&iy=0&&iz=0&&ix=0&&iy=0&&iz=0&&ix=0&&iy=0&&iz=0&&ix=0&&iy=0&&iz=mn) { fprintf(stderr,"PAINT: c = %d. Not be %d< c <%d\n\n",c,mn,mx); return; } cc = vp.gp[y*vp.xs+x]; if (cc>mx || cc0) { if (vp.gp[y*vp.xs+x-1]>mx || vp.gp[y*vp.xs+x-1]mx || vp.gp[y*vp.xs+k]=0 && y-1=mn) { paint(vp, i, y-1, mn, mx, c, m); } if (Xabs(m)==8) { // 8-neighborhood * if (i-1>=0) { if (vp.gp[j-1]<=mx && vp.gp[j-1]>=mn) { paint(vp, i-1, y-1, mn, mx, c, m); } } if (i+1=mn) { paint(vp, i+1, y-1, mn, mx, c, m); } } } } if (y+1>=0 && y+1=mn) { paint(vp, i, y+1, mn, mx, c, m); } if (Xabs(m)==8) { // 8-neighborhood if (i-1>=0) { if (vp.gp[j-1]<=mx && vp.gp[j-1]>=mn) { paint(vp, i-1, y+1, mn, mx, c, m); } } if (i+1=mn) { paint(vp, i+1, y+1, mn, mx, c, m); } } } } } return; } /** void paint3d(WSGraph vp, int x, int y, int z, int mn, int mx, int c, int m) 3Dグラフィックの塗りつぶし.@n 3Dグラフィック vpの点(x,y,z)から始めて, mn〜mx の輝度値を c で塗りつぶす. @param vp グラフィックデータ構造体. @param x,y,z 塗りつぶしを始める点の座標. @param mn 塗りつぶされる輝度値の最小値 @param mx 塗りつぶされる輝度値の最大値. @param c 塗りつぶしの輝度値. @param m モード.マイナスの場合は途中経過を表示. @n @b +-8: 8近傍の塗りつぶし @n @b その他: 4近傍の塗りつぶし 注:プログラム中で EGMAX を使用. */ void paint3d(WSGraph vp, int x, int y, int z, int mn, int mx, int c, int m) { int i; _paint_3d(vp, x, y, z, mn, mx, SWORDMAX, m); for (i=0; imx || cc=0) { j = (z-1)*ps+y*vp.xs+x; if (vp.gp[j]<=mx && vp.gp[j]>=mn) _paint_3d(vp, x, y, z-1, mn, mx, c, m); } if (z+1=mn) _paint_3d(vp, x, y, z+1, mn, mx, c, m); } } } return; } /** void bline(BSGraph vp, int x1, int y1, int x2, int y2, int cc) 2Dのラインの描画.@n 点(x1,y1)から点(x2,y2)へ濃度 ccの線を引く. @param vp 操作対象となるグラフィックデータ構造体. @param x1, y1 線の始点の座標. @param x2, y2 線の終点の座標. @param cc 線の濃度. @par 使用例 @code line(vp, 100, 200, 300, 300, 200); // (100,200)から(300,300)へ濃度 200の線を引く @endcode */ void bline(BSGraph vp, int x1, int y1, int x2, int y2, int cc) { int thresh=0, index; int xunit=1; int yunit=1; int xdiff=x2-x1; int ydiff=y2-y1; if (xdiff<0) { xdiff = -xdiff; xunit = -1; } if (ydiff<0) { ydiff = -ydiff; yunit = -1; } if (xdiff>ydiff) { for (index=0; index=xdiff) { thresh = thresh - xdiff; y1 = y1 + yunit; } } } else { for (index=0; index=ydiff) { thresh = thresh - ydiff; x1 = x1 + xunit; } } } } /** void line(WSGraph vp, int x1, int y1, int x2, int y2, int cc) 2Dのラインの描画.@n 点(x1,y1)から点(x2,y2)へ濃度 ccの線を引く. @param vp 操作対象となるグラフィックデータ構造体. @param x1,y1 線の始点の座標. @param x2,y2 線の終点の座標. @param cc 線の濃度. @par 使用例 @code line(vp, 100, 200, 300, 300, 200); // (100,200)から(300,300)へ濃度 200の線を引く @endcode */ void line(WSGraph vp, int x1, int y1, int x2, int y2, int cc) { int thresh=0, index; int xunit=1; int yunit=1; int xdiff=x2-x1; int ydiff=y2-y1; if (xdiff<0) { xdiff = -xdiff; xunit = -1; } if (ydiff<0) { ydiff = -ydiff; yunit = -1; } if (xdiff>ydiff) { for (index=0; index=xdiff) { thresh = thresh - xdiff; y1 = y1 + yunit; } } } else { for (index=0; index=ydiff) { thresh = thresh - ydiff; x1 = x1 + xunit; } } } } /** void triangle(WSGraph vp, int x1, int y1, int x2, int y2, int x3, int y3, int cc, int mode) 2Dの三角形の描画.@n 点(x1,y1),(x2,y2),(x3,y3)の三点を頂点とした三角形を描く.@n 線の濃度は cc. modeが 1以上なら,三角形の内部を塗りつぶす. @param vp 操作対象となるグラフィックデータ構造体. @param (x1,y1),(x2,y2),(x3,y3) 三角形の頂点の座標. @param cc 線の濃度. @param mode @b ON なら三角形の内部の0〜ccをccで塗りつぶす. @par 使用例 @code // (100,100),(100,200),(200,100)を頂点とした三角形(直角三角形)を描き,内部を塗りつぶす triangle(vp, 100, 100, 100, 200, 200, 100, 1000, ON); @endcode */ void triangle(WSGraph vp, int x1, int y1, int x2, int y2, int x3, int y3, int cc, int mode) { line(vp, x1, y1, x2, y2, cc); line(vp, x2, y2, x3, y3, cc); line(vp, x3, y3, x1, y1, cc); if (mode==ON) { int i, j, minx, miny, maxx, maxy; minx = maxx = x1; miny = maxy = y1; minx = Min(x2, minx); minx = Min(x3, minx); miny = Min(y2, miny); miny = Min(y3, miny); maxx = Max(x2, maxx); maxx = Max(x3, maxx); maxy = Max(y2, maxy); maxy = Max(y3, maxy); for (j=miny; j<=maxy; j++) { for (i=minx; i<=maxx; i++) { if (isinctri(x1, y1, x2, y2, x3, y3, i, j)) Px(vp, i, j) = cc; } } } return; } /** int isinctri(int x1, int y1, int x2, int y2, int x3, int y3, int xx, int yy) 点(xx, yy) が三角形の中に含まれているか判定する @retval TRUE (xx,yy) は三角形 (x1,y1)-(x2,y2)-(x3,y3)の内部にある. @retval FALSE (xx,yy) は三角形 (x1,y1)-(x2,y2)-(x3,y3)の内部にない. */ int isinctri(int x1, int y1, int x2, int y2, int x3, int y3, int xx, int yy) { int cx, cy; cx = (x1 + x2 + x3)/3; cy = (y1 + y2 + y3)/3; if (isCrossLine(x1, y1, x2, y2, xx, yy, cx, cy)<0) return FALSE; if (isCrossLine(x1, y1, x3, y3, xx, yy, cx, cy)<0) return FALSE; if (isCrossLine(x2, y2, x3, y3, xx, yy, cx, cy)<0) return FALSE; return TRUE; } /** void box(WSGraph vp, int x1, int y1, int x2, int y2, int cc, int mode) 点(x1,y1)-(x2,y2)を対角とした四角形を描く.線の濃度は cc.@n modeが 1以上なら,四角形の内部を塗りつぶす. @param vp 操作対象となるグラフィックデータ構造体. @param (x1,y1)-(x2,y2) 四角形の対角の座標. @param cc 線の濃度. @param mode @b ON なら四角形の内部の0〜ccをccで塗りつぶす. @par 使用例 @code box(vp, 100, 100, 200, 200, 1000, 0); // (100,100),(200,200)を対角とした四角形を描く @endcode */ void box(WSGraph vp, int x1, int y1, int x2, int y2, int cc, int mode) { line(vp, x1, y1, x2, y1, cc); line(vp, x2, y1, x2, y2, cc); line(vp, x2, y2, x1, y2, cc); line(vp, x1, y2, x1, y1, cc); if (mode==ON) { paint(vp, (x1+x2)/2, (y1+y2)/2, 0, cc-1, cc, 4); } return; } /** void bline3d(BSGraph gd, int x1, int y1, int z1, int x2, int y2, int z2, int cc) 3Dのラインの描画.点(x1,y1,z1)から点(x2,y2,z2)へ濃度 ccの線を引く. @param gd 操作対象となるグラフィックデータ構造体. @param x1, y1, z1 線の始点の座標. @param x2, y2, z2 線の終点の座標. @param cc 線の濃度. */ void bline3d(BSGraph gd, int x1, int y1, int z1, int x2, int y2, int z2, int cc) { int i; int xx, yy, zz, dx, dy, dz; int ux=1, uy=1, uz=1; int sx=0, sy=0, sz=0; dx = x2 - x1; dy = y2 - y1; dz = z2 - z1; if (dx<0) { dx = -dx; ux = -1; } if (dy<0) { dy = -dy; uy = -1; } if (dz<0) { dz = -dz; uz = -1; } xx = x1; yy = y1; zz = z1; set_bdat(gd, xx, yy, zz, cc); if (dx>=dy && dx>=dz) { for (i=1; i<=dx; i++) { xx = xx + ux; sy = sy + dy; sz = sz + dz; if (sy>dx) { sy = sy - dx; yy = yy + uy; } if (sz>dx) { sz = sz - dx; zz = zz + uz; } set_bdat(gd, xx, yy, zz, cc); } } else if (dy>dx && dy>=dz) { for (i=1; i<=dy; i++) { yy = yy + uy; sx = sx + dx; sz = sz + dz; if (sx>dy) { sx = sx - dy; xx = xx + ux; } if (sz>dy) { sz = sz - dy; zz = zz + uz; } set_bdat(gd, xx, yy, zz, cc); } } else { for (i=1; i<=dz; i++) { zz = zz + uz; sx = sx + dx; sy = sy + dy; if (sx>dz) { sx = sx - dz; xx = xx + ux; } if (sy>dz) { sy = sy - dz; yy = yy + uy; } set_bdat(gd, xx, yy, zz, cc); } } } /** void line3d(WSGraph gd, int x1, int y1, int z1, int x2, int y2, int z2, int cc) 3Dのラインの描画.点(x1,y1,z1)から点(x2,y2,z2)へ濃度 ccの線を引く. @param gd 操作対象となるグラフィックデータ構造体. @param x1, y1, z1 線の始点の座標. @param x2, y2, z2 線の終点の座標. @param cc 線の濃度. */ void line3d(WSGraph gd, int x1, int y1, int z1, int x2, int y2, int z2, int cc) { int i; int xx, yy, zz, dx, dy, dz; int ux=1, uy=1, uz=1; int sx=0, sy=0, sz=0; dx = x2 - x1; dy = y2 - y1; dz = z2 - z1; if (dx<0) { dx = -dx; ux = -1; } if (dy<0) { dy = -dy; uy = -1; } if (dz<0) { dz = -dz; uz = -1; } xx = x1; yy = y1; zz = z1; set_idat(gd, xx, yy, zz, cc); if (dx>=dy && dx>=dz) { for (i=1; i<=dx; i++) { xx = xx + ux; sy = sy + dy; sz = sz + dz; if (sy>dx) { sy = sy - dx; yy = yy + uy; } if (sz>dx) { sz = sz - dx; zz = zz + uz; } set_idat(gd, xx, yy, zz, cc); } } else if (dy>dx && dy>=dz) { for (i=1; i<=dy; i++) { yy = yy + uy; sx = sx + dx; sz = sz + dz; if (sx>dy) { sx = sx - dy; xx = xx + ux; } if (sz>dy) { sz = sz - dy; zz = zz + uz; } set_idat(gd, xx, yy, zz, cc); } } else { for (i=1; i<=dz; i++) { zz = zz + uz; sx = sx + dx; sy = sy + dy; if (sx>dz) { sx = sx - dz; xx = xx + ux; } if (sy>dz) { sy = sy - dz; yy = yy + uy; } set_idat(gd, xx, yy, zz, cc); } } } /** void circle(WSGraph gd, int x, int y, int r, int cc, int mode) 2Dの円の描画.点(x,y)を中心に半径rで濃度 ccの円を書く. @param gd 操作対象となるグラフィックデータ構造体. @param x, y 円の中心の座標. @param r 円の半径. @param cc 線の濃度. @param mode @b ON なら円の内部の 0〜ccを ccで塗りつぶす. */ void circle(WSGraph gd, int x, int y, int r, int cc, int mode) { double yy, dy, dt; int i, nn, cx; int ix, iy, ux=1; int *px, *py; if (r<=0) return; px = (int*)malloc(sizeof(int)*(r+1)); py = (int*)malloc(sizeof(int)*(r+1)); if (px==NULL || py==NULL) { free(px); free(py); return; } ix = 0; iy = r; yy = (double)r; nn = 0; px[0] = ix; py[0] = iy; cx = (y+iy)*gd.xs + (x+ix); gd.gp[cx] = cc; while(iy>=ix) { ix = ix + ux; dt = -ux/yy; dy = ix*dt; yy = yy + dy; iy = (int)yy; set_idat(gd, x+ix, y+iy, 0, cc); nn++; px[nn] = ix; py[nn] = iy; } for (i=0; i<=nn; i++) { ix = py[nn-i]; iy = px[nn-i]; set_idat(gd, x+ix, y+iy, 0, cc); } for (i=0; i<=nn; i++) { ix = py[i]; iy = -px[i]; set_idat(gd, x+ix, y+iy, 0, cc); } for (i=0; i<=nn; i++) { ix = px[nn-i]; iy = -py[nn-i]; set_idat(gd, x+ix, y+iy, 0, cc); } for (i=0; i<=nn; i++) { ix = -px[i]; iy = -py[i]; set_idat(gd, x+ix, y+iy, 0, cc); } for (i=0; i<=nn; i++) { ix = -py[nn-i]; iy = -px[nn-i]; set_idat(gd, x+ix, y+iy, 0, cc); } for (i=0; i<=nn; i++) { ix = -py[i]; iy = px[i]; set_idat(gd, x+ix, y+iy, 0, cc); } for (i=0; i<=nn; i++) { ix = -px[nn-i]; iy = py[nn-i]; set_idat(gd, x+ix, y+iy, 0, cc); } if (mode==ON) paint(gd, x, y, 0, cc-1, cc, 4); free(px); free(py); } /** void circle3d(WSGraph vp, vector ox, vector ex, int rr, int cc, int mode) 3D的な円の描画. @param gd 操作対象となるグラフィックデータ構造体. @param ox 円の中心の座標ベクトル. @param ex 円の中心の法線ベクトル. @param rr 円の半径. @param cc 線の濃度. @param mode @b ON なら円の内部の 0〜ccを ccで塗りつぶす. */ void circle3d(WSGraph gd, vector ox, vector ex, int rr, int cc, int mode) { vector oz; WSGraph vp; vp = make_WSGraph(2*rr+3, 2*rr+3, 1); if (vp.gp==NULL) return; circle(vp, rr+1, rr+1, rr, cc, mode); oz = set_vector((vp.xs-1)/2., (vp.ys-1)/2., 0.0); ex = unit_vector(ex); local2world(gd, vp, ox, oz, ex, NULL, NULL); free(vp.gp); } /** void pool(WSGraph gd, vector a, vector b, int rr, int cc) 3D的な円柱の描画.中身はccで塗りつぶされる. @param gd 操作対象となるグラフィックデータ構造体. @param a 円柱の一方の底面の円の中心の座標ベクトル. @param b 円柱のもう一方の底面の円の中心の座標ベクトル. @param rr 円柱の半径. @param cc 線と塗りつぶしの濃度. */ void pool(WSGraph gd, vector a, vector b, int rr, int cc) { int i, ll, cz; vector ox, oz, ev; WSGraph vp, px; ox = sub_vector(b, a); ll = (int)(ox.n + 0.5); vp = px = make_WSGraph(2*rr+3, 2*rr+3, ll); if (vp.gp==NULL) return; for (i=0; i=0 && kvp.zs-s-1) zz = (vp.zs-s-1)/RZxy; } for (j=0; j<=2*nn; j++) { fi = dt*j; cf = cos(fi); sf = sin(fi); xx = r*sn*cf + a.x; yy = r*sn*sf + a.y; if (mode==-1) { if (xxvp.xs-s-1) xx = (double)(vp.xs-s-1); if (yy>vp.ys-s-1) yy = (double)(vp.ys-s-1); } set_wdat(vp, xx, yy, zz, cc, rb); } } } return; } /** WSGraph x_reverse_wsg(WSGraph vp) グラフィックデータの x軸を反転させる. @param vp 操作対象となるグラフィックデータ構造体. @return 反転したグラフィックデータ. */ WSGraph x_reverse_wsg(WSGraph vp) { int i, j, cy; WSGraph wp; wp = make_WSGraph(vp.xs, vp.ys, 1); if (wp.gp==NULL) { memset(&wp, 0, sizeof(WSGraph)); wp.state = JBXL_GRAPH_MEMORY_ERROR; return wp; } for (j=0; jEPS && nv.n!=1.0) { nv.x = nv.x/nv.n; nv.y = nv.y/nv.n; nv.z = nv.z/nv.n; } if (nv.z<-1.0) nv.z = -1.0; if (nv.z> 1.0) nv.z = 1.0; *cst = nv.z; *snt = sqrt(1.0-nv.z*nv.z); if (*snt=cc) { rb->xmax = Max(rb->xmax, i); rb->ymax = Max(rb->ymax, j); rb->zmax = Max(rb->zmax, k); rb->xmin = Min(rb->xmin, i); rb->ymin = Min(rb->ymin, j); rb->zmin = Min(rb->zmin, k); } } if (blank!=0) { rb->xmax += blank; rb->ymax += blank; rb->zmax += blank; rb->xmin -= blank; rb->ymin -= blank; rb->zmin -= blank; rb->xmin = Max(rb->xmin, 0); rb->ymin = Max(rb->ymin, 0); rb->zmin = Max(rb->zmin, 0); rb->zmax = Min(rb->zmax, vp.zs-1); } xp.xs = rb->xmax - rb->xmin + 1; xp.ys = rb->ymax - rb->ymin + 1; xp.zs = rb->zmax - rb->zmin + 1; xp = make_WSGraph(xp.xs, xp.ys, xp.zs); if (xp.gp==NULL) { xp.state = JBXL_GRAPH_MEMORY_ERROR; return xp; } for (i=0; izmin) + vp.xs*(j+rb->ymin) + (i+rb->xmin); if (vp.gp[ax]>=cc) xp.gp[cx] = vp.gp[ax]; } } } return xp; } /** void set_around(WSGraph vp, int cc) 2Dグラフィックデータの縁の部分の輝度値を ccにする. @param vp 操作対象となるグラフィックデータ構造体. @param cc データの縁に設定する輝度値. */ void set_around(WSGraph vp, int cc) { int i, px1, px2; for (i=0; i