/* * BSPLINE.C * * Matthew Dillon. * Public Domain (no Copyrights whatsoever) * * -Assumes AZTEC compilation, +L (32 bit ints), with all AMIGA symbols * precompiled. Additionally expects certain typedefs and routines * found in MY.LIB, as well as some MY.LIB #include files. * * An experienced programmer can remove the MY.LIB dependancies * (openlibs() call), and figure out what typedefs have been assumed if * he wishes to compile the program. You can also simply extract the * Bezier functions for your own use. * * BSPLINE EQUATIONS: * * c(t) = T(t)BP * * T(t) = (t^3 t^2 t 1) P= ( Pi-1 ) * B = ( -1 3 -3 1 ) ( Pi ) * ( 3 -6 3 0 ) ( Pi+1 ) * ( -3 0 3 0 ) ( Pi+2 ) * ( 1 4 1 0 ) * * t: range 0 to 1 * C: coordinate matrix 1xD matrix (D = dimensions) * B: Bspline matrix 4x4 * P: Ctrl. Point matrix 4xD matrix (D = dimensions) * * using D = 2. For B-Spline, must loop through all control points * beginning at Pi+1 and ending at Pend-2 */ #include #include #define SHIFTS 9 #define ONE (1<RPort; SetAPen(Rp, 3); SetDrMd(Rp, COMPLEMENT); setpoint(Pts, 0, 32, 32); setpoint(Pts, 1, 40, 40); setpoint(Pts, 2, 100, 50); setpoint(Pts, 3, 200, 60); Npts = 4; setbounds(Pts, Npts); while (notdone) { short mx, my, mm = 0; WaitPort(Win->UserPort); while (mess = GetMsg(Win->UserPort)) { switch(mess->Class) { case CLOSEWINDOW: notdone = 0; break; case NEWSIZE: setbounds(Pts, Npts); break; case GADGETUP: case GADGETDOWN: { gg = mess->Class; gy = po->VertPot / 256; } break; case MOUSEBUTTONS: switch(mess->Code) { case SELECTDOWN: pt = getpoint(Pts, Npts, mess->MouseX, mess->MouseY); switch(mode) { case 0: mm = 1; mx = mess->MouseX; my = mess->MouseY; goto break2; case 1: if (pt < 0) pt = 0; if (Npts != MAXPTS) { bmov(Pts[pt], Pts[pt+1], (Npts-pt)*sizeof(Pts[0])); Pts[pt][0] = mess->MouseX; Pts[pt][1] = mess->MouseY; ++Npts; } break; case 2: if (pt >= 0 && pt < Npts) { bmov(Pts[pt+1], Pts[pt], (Npts-pt)*sizeof(Pts[0])); --Npts; } break; } clearall(); drawcurve(Pts, Npts); drawpoints(Pts, 0, Npts); break; case SELECTUP: pt = -1; break; } break2: break; case MENUPICK: switch(MENUNUM(mess->Code)) { case 0: mode = ITEMNUM(mess->Code); break; case 1: drawpoints(Pts, 0, Npts); Display = ITEMNUM(mess->Code); /* 0=cross 1=nums */ drawpoints(Pts, 0, Npts); } break; case MOUSEMOVE: if (gg == GADGETDOWN) { gy = po->VertPot / 256; break; } if (mode == 0 || mode == 1) { mm = 1; mx = mess->MouseX; my = mess->MouseY; } break; default: break; } ReplyMsg(mess); } if (mm && pt >= 0) { register int i; register int n; i = (pt - 3 < 0) ? 0 : pt - 3; n = (i + 7 > Npts) ? Npts - i : 7; drawpoints(Pts, pt, pt+1); drawcurve(&Pts[i], n); setpoint(Pts, pt, mx, my); drawcurve(&Pts[i], n); drawpoints(Pts, pt, pt+1); } if (gg) { char buf[32]; if (gg == GADGETUP) gg = 0; if (gy + 1 >= 0 && gy + 1 != Step) { Step = gy + 1; sprintf(buf, "gran: %4ld/%ld", Step, ONE); clearall(); drawcurve(Pts, Npts); drawpoints(Pts, 0, Npts); Move(Rp, Ux + 1, Uy + 16); Text(Rp, buf, strlen(buf)); } } } exiterr(1, NULL); } exiterr(n, str) char *str; { if (n) { if (str) puts(str); if (Win) { uninit_menu(Win); CloseWindow(Win); } closelibs(-1); exit(1); } } setbounds(a, na) register long *a; { Ux = Win->BorderLeft; Uy = Win->BorderTop; Lx = Win->Width - Win->BorderRight; Ly = Win->Height- Win->BorderBottom + 1; clearall(); drawcurve(a, na); drawpoints(a, 0, na); } setpoint(a, pt, x, y) register short a[4][2]; { a[pt][0] = x; a[pt][1] = y; } getpoint(a, na, x, y) register short a[][2]; { register short i, bi; register long r, br; for (i = bi = 0, br = 0x7FFFFFFF; i < na; ++i) { r = (x-a[i][0])*(x-a[i][0]) + (y-a[i][1])*(y-a[i][1])*3; if (r < br) { bi = i; br = r; } } return(bi); } clearall() { SetAPen(Rp, 0); SetDrMd(Rp, JAM2); RectFill(Rp, Ux, Uy, Lx - 1, Ly - 1); SetAPen(Rp, 3); SetDrMd(Rp, COMPLEMENT); } #define S10(x) ((x) >> SHIFTS) #define S20(x) ((x) >> (2*SHIFTS)) /* * So I can use integer arithmatic, I am defining 512 as 1 (as far * as the mathematics go), which means that I must divide any power * multiplication by 512^(n-1). E.G. .5^2 = .25 ... to make 256^2 * equal 128, I must divide by 512^1 */ static short Array[ONE+4][2]; /* hold points to plot */ drawcurve(a, na) register short a[][2]; { long mr[4]; register short n, i, t; long tt, ttt; short last; for (i = 1; i < na - 2; ++i) { for (t = n = last = 0; t <= ONE; t += Step) { oncemore: tt = t * t; ttt= tt* t; mr[0] = -S20(ttt/6) + S10(tt/2) - t/2 + ONE/6; mr[1] = S20(ttt/2) - S10(tt) + ONE*2/3; mr[2] = -S20(ttt/2) + S10(tt/2) + t/2 + ONE/6; mr[3] = S20(ttt/6); Array[n][0] = (mr[0] * a[i-1][0] + mr[1] * a[i][0] + mr[2] * a[i+1][0] + mr[3] * a[i+2][0]) >> SHIFTS; Array[n][1] = (mr[0] * a[i-1][1] + mr[1] * a[i][1] + mr[2] * a[i+1][1] + mr[3] * a[i+2][1]) >> SHIFTS; if (++n == ONE + 4) { --n; puts("software error: OVERFLOW"); } } if (last == 0 && t > ONE) { t = ONE; last = 1; goto oncemore; } Move(Rp, Array[0][0], Array[0][1]); PolyDraw(Rp, n, Array); } } drawpoints(a, is, ie) register short a[][2]; { register short i; for (i = is; i < ie; ++i) { if (Display) { char buf[32]; Move(Rp, a[i][0], a[i][1]); Draw(Rp, a[i][0], a[i][1]); Move(Rp, a[i][0] - 16, a[i][1] + 4); sprintf(buf, "%ld", i); Text(Rp, buf, strlen(buf)); } else { Move(Rp, a[i][0] - 2, a[i][1]); Draw(Rp, a[i][0] + 2, a[i][1]); Move(Rp, a[i][0], a[i][1] - 2); Draw(Rp, a[i][0], a[i][1] + 2); } } } /* * GADGET ROUTINES! ------------------------------------------------ */ #define NG(nn) &Gadgets[nn+1] #define G_YGLOB 1 #define G_XGLOB 2 XPI Props[] = { { AUTOKNOB|FREEVERT , 0, 0, 0x1FFF, 0x1FFF } }; IM Images[] = { { 0,0,2,1,1, NULL, 1, 0, NULL }, }; GADGET Gadgets[] = { { NULL, -15, 11, 15, -19, GADGIMAGE|GADGHCOMP|GRELRIGHT|GRELHEIGHT, GADGIMMEDIATE|RIGHTBORDER|RELVERIFY,PROPGADGET, (APTR)&Images[0],NULL,NULL,0,(APTR)&Props[0], G_YGLOB, 0 }, }; GADGET *Gc; long GUx, GUy; init_gadgets(nw, ppo) NW *nw; XPI **ppo; { nw->FirstGadget = &Gadgets[0]; *ppo = &Props[0]; } /* * MENU ROUTINES! ----------------------------------------------------- */ ITEXT Itext[] = { { 0,1,JAM2,0,0,NULL,(UBYTE *)" Move", NULL }, { 0,1,JAM2,0,0,NULL,(UBYTE *)" Add", NULL }, { 0,1,JAM2,0,0,NULL,(UBYTE *)" Delete",NULL }, { 0,1,JAM2,0,0,NULL,(UBYTE *)" Cross", NULL }, { 0,1,JAM2,0,0,NULL,(UBYTE *)" Number",NULL } }; MENUITEM Item0[] = { { &Item0[1], 0, 0, 8*11, 8, CHECKIT|ITEMENABLED|COMMSEQ|HIGHCOMP|ITEMTEXT, 0xFE, (APTR)&Itext[0], NULL, 'M', NULL, NULL }, { &Item0[2], 0, 8, 8*11, 8, CHECKIT|ITEMENABLED|COMMSEQ|HIGHCOMP|ITEMTEXT, 0xFD, (APTR)&Itext[1], NULL, 'A', NULL, NULL }, { NULL, 0,16, 8*11, 8, CHECKIT|ITEMENABLED|COMMSEQ|HIGHCOMP|ITEMTEXT, 0xFB, (APTR)&Itext[2], NULL, 'D', NULL, NULL } }; MENUITEM Item1[] = { { &Item1[1], 0, 0, 8*11, 8, CHECKIT|ITEMENABLED|COMMSEQ|HIGHCOMP|ITEMTEXT, 0xFE, (APTR)&Itext[3], NULL, 'C', NULL, NULL }, { NULL , 0, 8, 8*11, 8, CHECKIT|ITEMENABLED|COMMSEQ|HIGHCOMP|ITEMTEXT, 0xFD, (APTR)&Itext[4], NULL, 'N', NULL, NULL } }; MENU Menu[] = { { &Menu[1], 0, 0,8*11, 8, MENUENABLED, "Control", &Item0[0] }, { NULL , 8*11,0,8*11, 8, MENUENABLED, "Display", &Item1[0] } }; init_menu(win) WIN *win; { SetMenuStrip(win, &Menu[0]); } uninit_menu(win) WIN *win; { ClearMenuStrip(win); }