#include #include #include "gui.H" ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// // Text button methods TextButton :: TextButton(char *txt, int xp, int yp, Display *d, Window w) : leng(strlen(txt)+1), x(xp), y(yp), sy(14), disp(d), win(w) { // set up all the important X11 data that // the text button will need to draw itself // the gc defining the text draw style gc = XCreateGC(disp, win, 0, 0); XSetForeground(disp, gc, 0); // The font used to draw the text is loaded // and installed into the gc font = XLoadFont(disp, "6x12"); font_s = XQueryFont(disp, font); XSetFont(disp, gc, font); // a copy is made of the text for the button text = new char[leng]; strcpy(text, txt); // the width of the text in pixels must be // recorded, in order to size the button sx = XTextWidth(font_s, text, leng); } void TextButton :: draw() { // clear the background XSetForeground(disp, gc, 0); XFillRectangle(disp, win, gc, x, y, sx, sy); // draw the frame XSetForeground(disp, gc, 1); XDrawRectangle(disp, win, gc, x, y, sx, sy); // draw the text XDrawString(disp, win, gc, x+2, y+sy-4, text, leng); } ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// // Row Box methods RowBox :: RowBox(int xp, int yp, int max_width, Display *d, Window w) : disp(d), win(w), x(xp), y(yp), sx(0), sy(2), max_sx(max_width), max_row_y(0), n(0) { // The row box is initially empty // The gc for the Row Box frame must be created gc = XCreateGC(disp, win, 0, 0); XSetForeground(disp, gc, 0); // storage for the list of buttons in this row box buttons = new TextButton *[20]; } RowBox :: ~RowBox() { int i; // destroys all buttons for(i=0; isizex() > max_sx-2) { sx=0; sy += 2 + max_row_y; buttons[n]->setpos(x+2,y+sy); max_row_y = buttons[n]->sizey(); } // resize the box if the new button forces the // row box to be taller if(buttons[n]->sizey() > max_row_y) max_row_y = buttons[n]->sizey(); // increase the width of the box's current row sx += 2 + buttons[n]->sizex(); // return the button ID of the new button n++; return n; } int RowBox :: pt_in(int x, int y) { int i; // find the button in which the user clicked for(i=0; ipt_in(x,y)) return(i+1); // return its ID return 0; // if none was clicked, return the null button ID } void RowBox :: draw() { // Clear the background XSetForeground(disp, gc, 1); XFillRectangle(disp, win, gc, x, y, sizex(), sizey()); // Draw the frame XSetForeground(disp, gc, 0); XDrawRectangle(disp, win, gc, x, y, sizex(), sizey()); // Draw each of the buttons int i; for(i=0; idraw(); } void RowBox :: setpos(int xp, int yp) { // translate the new absoulte position of the row box // into a translation from its old position int i, dx = xp-x, dy = yp-y; // move each of the buttons by the motion vector for(i=0; ixpos() += dx; buttons[i]->ypos() += dy; } // update the current position x = xp; y = yp; } void ImageWindow :: remap_image() { int dummy; unsigned char d; remappeddata = new(unsigned char [xSize*ySize]); // remap the gray levels to match the colormap // remap all colors plus 1, unless they are greater // than 253, which we remap to 100% white (0). // the colormap has 0 as white and 1 as black, as per // X11 convention for(dummy=0; dummy253) remappeddata[dummy] = 0; else remappeddata[dummy] = d+1; } } int ImageWindow :: load_image(istream &fp) { char c; int dummy; // Standard PPM (P6) file reading code fp.get(c); if(c!='P') { fprintf(stderr,"file of wrong format\n"); return(NULL); } fp.get(c); if(c!='5') { fprintf(stderr,"file of wrong format\n"); return(NULL); } fp.get(c); fp.get(c); while (c=='#') { while(c !='\n') fp.get(c); fp.get(c); } if(c!='#') fp.putback(c); fp >> xSize >> ySize >> dummy; fp.get(c); cerr << xSize << endl; cerr << ySize << endl; // allocate the actual image data imagedata = new(unsigned char[xSize*ySize]); // allocate the colormap remapped image data remappeddata = new(unsigned char[xSize*ySize]); int i; for(i=0; iadd_button("Delete Last Point"); clear = buttons->add_button("Clear Points"); grid = buttons->add_button("Fit Grid"); done = buttons->add_button("Done"); // place the rowbox so that its bottom is in line // with the bottom of the window buttons->setpos(1,winy - buttons->sizey() - 1); max_points = 0; //cerr << "enter the number of points in the i and j directions" // << endl; // cin >> i_max >> j_max; i_max = 40; j_max = 40; // cerr << "enter the grid spacing divided by the line width" // << endl; // cin >> spacing_ratio; spacing_ratio = 10.0; // pop up the window display_image_window(); redraw_window(); XFlush(disp); // hand over control to the input parsing system receive_input(); } } void ImageWindow :: initialize_colormap() { XColor color; int loop; // The colormap is as follows: // Colormap slot # Gray Level // 0 255 (white, as per X11 standard) // 1 0 (black, as per X11 standard) // 2 1 // 3 2 // ... // 253 252 // 254 253 // 255 Purple (highlight color) gc = XCreateGC(disp, win, 0, 0); map = XCreateColormap(disp, win, DefaultVisual(disp, 0), 0); // white color.pixel = 0; color.red = color.blue = color.green = 255<<8; XAllocColor(disp,map, &color); // black-white spread for(loop=0; loop<254; loop++) { color.pixel = loop; color.red = color.blue = color.green = (loop+1)<<8; XAllocColor(disp, map, &color); } // Highlight color color.pixel = 255; color.green = color.blue = 64<<8; color.red = 255<<8; XAllocColor(disp, map, &color); // install the colormap XSetWindowColormap(disp, win, map); // gotta do this for the HP's. I hate this. lmb 9/10/95 XInstallColormap(disp, map); } void ImageWindow :: display_image_window() { // map the simple window XMapRaised(disp, win); } void ImageWindow :: draw_image() { // draw the outer window frame XSetForeground(disp, gc, 0); XDrawRectangle(disp, win, gc, 0, 0, xSize+3, ySize+3); // draw the inner window frame XSetForeground(disp, gc, 1); XDrawRectangle(disp, win, gc, 1, 1, xSize+1, ySize+1); // draw the image itself XPutImage(disp, win, gc, displayable, 0, 0, 2, 2, xSize, ySize); } void ImageWindow :: draw_points() { int loop; // drop a small rectangle in the image at // the position of each of the points in the // point list for(loop=0; loopdraw(); // draw the selected points draw_points(); // do it _now_ XFlush(disp); } void ImageWindow :: gridding() { int loop; // must have at least 4 mappings of row,col -> x,y // or else the mapping is under-constrained if(max_points>=4) { // solve the system for the projection find_projective_transformation(dot_points,image_points, max_points,projection); // invert the transformation inverse = invert(projection); // Draw the grid // iso-column lines XSetForeground(disp,gc,255); dvector p1(3,1.0), p2(3,1.0), pp1(3,1.0), pp2(3,1.0); for(loop = 0; looppt_in(x,y)) { if(clicked==del) // delete the last point { if(max_points) max_points--; redraw_window(); } else if(clicked==clear) // clear all points { max_points = 0; redraw_window(); } else if(clicked==grid) // fit a projective transformation { // to the data gridding(); } else if(clicked==done) // done - exit and write file { d = 1; } else cerr << "not a recognized button\n"; // oops... this // case _really_ // shouldn't happen } else // click on the image area { image_points(0,max_points) = x - 2; // correct for the fact that image_points(1,max_points++) = y - 2; // the image is drawn at 2,2 redraw_window(); // not 0,0 (the borders occupy // 0 and 1 cerr << "enter the i j position of the new point (separated by spaces)\n"; cin >> dot_points(0,max_points-1) >> dot_points(1,max_points-1); } return d; } void ImageWindow :: receive_input() { // Standard X11 event loop // set up the event mask to grab the button clicks and // exposures (for redraw) XSelectInput(disp, win, ButtonPressMask | ExposureMask); XEvent ev; int d=0; while(!d) { // get the event XNextEvent(disp, &ev); switch(ev.type) { // click - check where the click was and dispatch it case ButtonPress : if(ev.xbutton.button==1 && (max_points=4) { // solve the system for the projective transformation find_projective_transformation(dot_points,image_points, max_points,projection); //invert the transformation inverse = invert(projection); // write out the max dimensions of the rows and columns ost << i_max << " " << j_max << endl; dvector p1(3,1.0), pp1(3,1.0); dvector p(3,1.0), pp(3,1.0); dvector *projections = new dvector[i_max*j_max]; int *flags = new int[i_max*j_max]; // for each row and column, use the transformation to map // i,j to x,y. If the x,y is in side the images bounds, // note the mapping i,j x,y to the points list and increment the // count of points. int count = 0; for(j = 0; j= 0.0 && pp[0] < xSize && pp[1] >= 0.0 && pp[1] < ySize) { count++; flags[i+j*i_max] = 1; } else flags[i+j*i_max] = 0; } int avg_count = 0; double sum = 0.0; // find the average distance between neighboring // grid points for(j = 0; j= 0 && // not off left edge li < i_max && // not off right edge lj >= 0 && // not off top edge lj < j_max) // not off bottom edge { if(li != i) { tmp = (int)(abs(projections[li+lj*i_max][0] - xval) * (1.0 - 2.0/spacing_ratio)); if(tmp < sizes[i+j*i_max]) sizes[i+j*i_max] = tmp; } if(lj != j) { tmp = (int)(abs(projections[li+lj*i_max][1] - yval) * (1.0 - 2.0/spacing_ratio)); if(tmp < sizes[i+j*i_max]) sizes[i+j*i_max] = tmp; } } } sizes[i+j*i_max]--; } ost << spacing_ratio << endl; ost << sum / (double)avg_count << endl; ost << count << endl; // write out the crossing information for(j = 0; j 0) XDrawRectangle(disp,win,gc, (int)(projections[i+j*i_max][0]+2-sz), (int)(projections[i+j*i_max][1]+2-sz), 2*sz,2*sz); } XFlush(disp); cerr << "press return to exit" << endl; getchar(); delete[] projections; delete[] flags, delete[] sizes; } }