/* curved.c - A minimal curve editor.*
Paul Haeerli - 1985 */
#include <gl/gl.h> #include <gl/device.h>
float endgeom[4][3]; float geom[100][3]; int pt[100];
#define ADDPOINT 1 #define MOVEPOINT 2 #define INSERTPOINT 3 #define DELETEPOINT 4 #define CHANGEPOINT 5 #define BACKGROUND 7 #define LINE 0 #define ROUND 1 #define SQUARE 2 #define MOUSEXMAP(x) ( (100.0*((x)-xorg))/xsize ) #define MOUSEYMAP(y) ( (100.0*((y)-yorg))/ysize )
short raster[] = { 0xf800, 0x8800, 0x8800, 0x8800, 0xf800, 0x7000, 0x8800, 0x8800, 0x8800, 0x7000, };
Fontchar chars[] = { {0,0,0, 0, 0,0}, {0,5,5,-2,-2,5}, {5,5,5,-2,-2,5} };
Matrix b_spline = { {-1.0/6.0, 1.0/2.0, -1.0/2.0, 1.0/6.0}, { 1.0/2.0, -1.0, 1.0/2.0, 0.0}, {-1.0/2.0, 0.0, 1.0/2.0, 0.0}, { 1.0/6.0, 2.0/3.0, 1.0/6.0, 0.0} };
Matrix lob_spline = { { 0.0, 0.0, 0.0, 0.0}, { 1.0/3.0, -2.0/3.0, 1.0/3.0, 0.0}, {-7.0/6.0, 4.0/3.0, -1.0/6.0, 0.0}, { 1.0, 0.0, 0.0, 0.0}, };
Matrix hib_spline = { {0.0, 0.0, 0.0, 0.0}, {0.0, 1.0/3.0, -2.0/3.0, 1.0/3.0}, {0.0, -1.0/2.0, 0.0, 1.0/2.0}, {0.0, 1.0/6.0, 2.0/3.0, 1.0/6.0}, };
Matrix c_spline = { {-0.5, 1.5, -1.5, 0.5}, { 1.0, -2.5, 2.0, -0.5}, {-0.5, 0.0, 0.5, 0.0}, { 0.0, 1.0, 0.0, 0.0} };
Matrix loc_spline = { { 0.0, 0.0, 0.0, 0.0}, { 0.5, -1.0, 0.5, 0.0}, {-1.5, 2.0, -0.5, 0.0}, { 1.0, 0.0, 0.0, 0.0} };
Matrix hic_spline = { {0.0, 0.0, 0.0, 0.0}, {0.0, 0.5, -1.0, 0.5}, {0.0, -0.5, 0.0, 0.5}, {0.0, 0.0, 1.0, 0.0} };
#define BSPLINE 100 #define LOBSPLINE 101 #define HIBSPLINE 102
int xsize, ysize; int xorg, yorg; float mx, my; int curmode = ADDPOINT; int points; int menu; main(argc,argv) int argc; char **argv; { prefposition(XMAXSCREEN/4,XMAXSCREEN*3/4,YMAXSCREEN/4, YMAXSCREEN*3/4); winopen("curved"); menu = defpup("curved %t|add|move|insert|delete|change"); defrasterfont(1,7,3,chars,10,raster); font(1); deflinestyle(1,0xf0f0); if (argc == 1) { defbasis(BSPLINE,b_spline); defbasis(LOBSPLINE,lob_spline); defbasis(HIBSPLINE,hib_spline); } else { defbasis(BSPLINE,c_spline); defbasis(LOBSPLINE,loc_spline); defbasis(HIBSPLINE,hic_spline); }
curveprecision(6); makeframe(); initdevices(); points = 0; while (1) getinput(); }
initdevices() { qdevice(MOUSEX); qdevice(MOUSEY); qdevice(LEFTMOUSE); qdevice(MENUBUTTON); qdevice(KEYBD); }
getinput() { Device dev; short val; int sel; do { if (!qtest()) mouseevent(2,mx,my); dev = qread(&val); switch (dev) { case MENUBUTTON: if (val) { sel = dopup(menu); if (sel>0) curmode = sel; }
font(1); break; case LEFTMOUSE: mouseevent(val,mx,my); break; case MOUSEX: mx = MOUSEXMAP(val); break; case MOUSEY: my = MOUSEYMAP(val); break; case KEYBD: switch (val) { case 'a': break; case 'i': curmode = INSERTPOINT; break; case 'm': curmode = MOVEPOINT; break; case 'd': curmode = DELETEPOINT; break; case 'c': curmode = CHANGEPOINT; break; }
break; case REDRAW: reshapeviewport(); makeframe(); break; }
} while (qtest()); }
int curpoint; int moving;
mouseevent(state,x,y) int state; float x, y; { int nextpoint; switch (curmode) { case ADDPOINT: if (state == 1) { curpoint = duppoint(points); geom[curpoint][0] = x; geom[curpoint][1] = y; pt[curpoint] = SQUARE; drawline(LINE); }
break; case MOVEPOINT: if (state == 1) { curpoint = findpoint(x,y); moving = 1; } else if (state == 2) { if (moving) { drawline(BACKGROUND); geom[curpoint][0] = x; geom[curpoint][1] = y; drawline(LINE); }
} else if (state == 0) moving = 0; break; case INSERTPOINT: if (state == 1) { curpoint = findpoint(x,y); if (curpoint < 0) curpoint = duppoint(points); else curpoint = duppoint(curpoint); drawline(BACKGROUND); geom[curpoint][0] = x; geom[curpoint][1] = y; pt[curpoint] = SQUARE; drawline(LINE); } break; case DELETEPOINT: if (state == 1) { curpoint = findpoint(x,y); if (curpoint >= 0) { drawline(BACKGROUND); delpoint(curpoint); drawline(LINE); }
}
break; case CHANGEPOINT: if (state == 1) { curpoint = findpoint(x,y); if (curpoint >= 0) { drawline(BACKGROUND); if (pt[curpoint] == ROUND) pt[curpoint] = SQUARE; else pt[curpoint] = ROUND; drawline(LINE); }
}
break; }
}
makeframe() { getorigin(&xorg,&yorg); getsize(&xsize,&ysize); ortho2(0.0,100.0,0.0,100.0); color(BACKGROUND); clear(); drawline(LINE); }
float ppdist(x1,y1,x2,y2) float x1,y1,x2,y2; { register float dx, dy; dx = x2-x1; if (dx<0) dx = -dx; dy = y2-y1; if (dy<0) dy = -dy; return dx+dy; }
float pldist(x,y,x1,y1,x2,y2) float x, y, x1, y1, x2, y2; { register float dx, dy, c;
dx = x2-x1; dy = y2-y1; c = dy*x1-dx*y1; }
findpoint(x,y) float x, y; { register float mindist; register int minpnt; register int i; float dist; mindist = 100000.0; minpnt = -1; for (i=0; i<points; i++) { dist = ppdist(geom[i][0],geom[i][1],x,y); if (dist<mindist) { mindist = dist; minpnt = i; }
}
return minpnt; }
findedge(x,y) float x, y; { register float mindist; register int minpnt; register int i; float dist; mindist = 100000.0; minpnt = -1; for (i=0; i<points; i++) { dist = ppdist(geom[i][0],geom[i][1],x,y); if (dist<mindist) { mindist = dist; minpnt = i; }
}
return minpnt; }
duppoint(pnt) int pnt; { register int i; for (i=points; i>pnt; i--) { geom[i][0] = geom[i-1][0]; geom[i][1] = geom[i-1][1]; pt[i] = pt[i-1]; }
points++; return pnt; }
delpoint(pnt) int pnt; { register int i; for (i=pnt; i<points; i++) { geom[i][0] = geom[i+1][0]; geom[i][1] = geom[i+1][1]; pt[i] = pt[i+1]; }
points--; }
drawline(c) int c; { register int i, j;
pt[0] = SQUARE; pt[points-1] = SQUARE; color(c); if (c == BACKGROUND) clear(); else { setlinestyle(1); move2(geom[0][0],geom[0][1]); for (i=0; i<points; i++) { draw2(geom[i][0],geom[i][1]); putsym(i); }
setlinestyle(0); move2(geom[0][0],geom[0][1]); for (i=1; i<points; i++) { if(pt[i] == SQUARE) { if(pt[i-1] == ROUND) { for (j=0; j<4; j++) { endgeom[j][0] = geom[i-2+j][0]; endgeom[j][1] = geom[i-2+j][1]; }
endgeom[3][0] = endgeom[2][0]; endgeom[3][1] = endgeom[2][1]; curvebasis(BSPLINE); crv(endgeom); draw2(geom[i][0],geom[i][1]); } else { draw2(geom[i][0],geom[i][1]); }
} else { if (pt[i-1] == SQUARE) { for (j=0; j<4; j++) { endgeom[j][0] = geom[i-2+j][0]; endgeom[j][1] = geom[i-2+j][1]; }
endgeom[0][0] = endgeom[1][0]; endgeom[0][1] = endgeom[1][1]; curvebasis(BSPLINE); crv(endgeom); } else { curvebasis(BSPLINE); crv(&geom[i-2][0]); } } } } }
putsym(i) register int i; { char buf[2]; cmov2(geom[i][0],geom[i][1]); if (pt[i] == SQUARE) buf[0] = 1; else buf[0] = 2; buf[1] = 0; charstr(buf); }
The charstr subroutine, cmov subroutine, deflinestyle subroutine, defpup subroutine, defrasterfont subroutine, dopup subroutine, font subroutine.