// turtle.h #ifndef _TURTLE_H #define _TURTLE_H #include class TG { private: int win; int W, H; int gPx,gPy,gPw,gPh; double gX1,gX2,gY1,gY2; double gSx, gSy, gCx, gCy; bool gPen, gShow; double gSin, gCos, gX, gY,gOldX,gOldY,gOldSin,gOldCos; double gOldAngle, gAngle; double gCursorSize; /*static const*/ double RADCON; int gIdx; double gPoints[40]; public: void rescale() { W = ucw_cmd(win,"w"); H = ucw_cmd(win,"h"); gSx = W/(gX2 - gX1); gSy = H/(gY2 - gY1); gCx = W - gSx*gX2; gCy = H - gSy*gY2; gX = 0; gY = 0; gCursorSize = (gX2 - gX1)/30; } void scale(double x1, double x2, double y1, double y2) { gX1 = x1; gX2 = x2; gY1 = y1; gY2 = y2; rescale(); } int scalex(double x) { return gCx + gSx*x + 0.5; } int scaley(double y) { return H - (gCy + gSy*y + 0.5); } void pen(bool up = true) { gPen = up; } void penup() { pen(false); } void plot(double x, double y) { int ix = scalex(x), iy = scaley(y); gX = x; gY = y; if (gPen) ucw_line_to(win,ix,iy); else { ucw_move_to(win,ix,iy); pen(); } } void fcolor(double r, double g, double b) { ucw_fcolour(win,r,g,b); } void bcolor(double r, double g, double b) { ucw_bcolour(win,r,g,b); } static unsigned long rgb(int ri, int rg, int rb) { return (unsigned long) ucw_rgb(ri,rg,rb); } void set_color(unsigned long clr, bool fground) { ucw_set_colour(win,(long)clr,(int)fground); } void rectangle(double x1, double y1, double x2, double y2) { ucw_rectangle(win,scalex(x1),scaley(y1),scalex(x2),scaley(y2)); } void ellipse(double x1, double y1, double x2, double y2) { ucw_ellipse(win,scalex(x1),scaley(y1),scalex(x2),scaley(y2)); } void start_poly() { penup(); gIdx = 0; } void add(double x, double y) { gPoints[gIdx++] = x; gPoints[gIdx++] = y; } void do_poly() { int i; add(gPoints[0],gPoints[1]); double x0 = gX, y0 = gY; for(i = 0; i < gIdx; i+=2) { double x = gPoints[i] - x0, y = gPoints[i+1] - y0; double sx = gCos*x - gSin*y + x0; double sy = gSin*x + gCos*y + y0; plot(sx,sy); } } void draw_cursor(double sz, double x, double y) { start_poly(); add(x-sz,y+sz); add(x+sz,y); add(x-sz,y-sz); do_poly(); penup(); plot(x,y); } void update_cursor() { ucw_cmd(win,"X"); ucw_fcolour(win,1,1,1); draw_cursor(gCursorSize,gX,gY); ucw_cmd(win,"X"); ucw_fcolour(win,0,0,0); } void turn(double angle) { if(gShow) update_cursor(); gAngle += angle; // note the -ve sign! ?? double rads = gAngle*RADCON; gSin = sin(rads); gCos = cos(rads); if(gShow) update_cursor(); } void left() { turn(90); } void right() { turn(-90); } void draw(double len) { if(gShow) update_cursor(); gX += gCos*len; gY += gSin*len; plot(gX,gY); if(gShow) update_cursor(); } void move(double len) { penup(); draw(len); } void show(bool yes=true) { if (yes != gShow) { update_cursor(); gShow = yes; } } void text(char *msg) { double old_x = gX, old_y = gY; ucw_text_out(win,msg); penup(); plot(old_x,old_y); } //using namespace std; using std::string; void text(const string& s) { text(s.c_str()); } void resize(int x0=-1, int y0=-1, int w=0, int h=0, char *title=NULL) { if (x0 > 0) { gPx = x0; gPy = y0; if (w > 0) { gPw = w; gPh = h; } } if (title) win = ucw_create_window(title,gPx,gPy,gPw,gPh); else ucw_size_window(win,gPx,gPy,gPw,gPh); } void on_top() { ucw_cmd(win,"T"); } void go_to(double x, double y) { if(gShow) update_cursor(); penup(); plot(x,y); if(gShow) update_cursor(); } void reset_angle() { gAngle = 0.0; gSin = 0.0; gCos = 1.0; } int width() { return ucw_cmd(win,"W"); } int height() { return ucw_cmd(win,"H"); } void setup(double vmin=100,double vmax=100) { gShow = false; ucw_rectangle(win,0,0,width(),height()); reset_angle(); scale(0,vmin,0,vmax); } TG(char *_name,int _W = 400, int _H = 400) { resize(450,200,_W,_H,_name); RADCON = 0.01745; setup(); } void init() { on_top(); rescale(); ucw_fcolour(win,0,0,0); go_to((gX2+gX1)/2,(gY2+gY1)/2); penup(); left(); pen(true); } }; struct TG_State { double mOldX,mOldY,mOldAngle,mOldSin,mOldCos; TG& mTg; TG_State(TG& tg) : mTg(tg) {} void save() { mOldX = mTg.gX; mOldY = mTg.gY; mOldSin = mTg.gSin; mOldCos = mTg.gCos; mOldAngle = mTg.gAngle; } void restore() { mTg.gSin = mOldSin; mTg.gCos = mOldCos; mTg.gAngle = mOldAngle; mTg.go_to(mOldX,mOldY); // move back to original pos.... } }; #endif