view main/plot/ginput.cc @ 0:6b33357c7561 octave-forge

Initial revision
author pkienzle
date Wed, 10 Oct 2001 19:54:49 +0000
parents
children
line wrap: on
line source

/*
 * Get graphical coordinates from screen
 * 
 * This contains bits of code hacked from the
 * X Consortium and from Octave. Please see the
 * appropriate licences. The rest is mine, and
 * you can do what you want with that part.
 * 
 * Andy Adler <adlera@ncf.ca> (C) 1997
 * 
 * Compile like this
 * mkoctfile -L/usr/X11R6/lib -lX11 -I/usr/X11R6/include/ ginput.cc 
 *
 * Please excuse the ugly code. I wrote while I was learning C.
 */

#include <octave/config.h>
#include <iostream.h>

#include <octave/pager.h>

#include <octave/defun-dld.h>
#include <octave/error.h>
#include <octave/help.h>
#include <octave/symtab.h>
#include <octave/oct-obj.h>
#include <octave/utils.h>

#include <X11/Xlib.h>
#include <X11/cursorfont.h>

#define maxpoints 100

DEFUN_DLD (ginput, args, nargout ,
  "[...] = ginput (...)\n\
\n\
GINPUT: gets points mouse clicks on the screen\n\
 \n\
[x,y]= ginput(axis)\n\
 x -> x coordinates of the points\n\
 y -> y coordinates of the points\n\
\n\
 axis -> if specified then the first 2 (or 4) clicks\n\
      must be on the appropriate axes. x and y (or just x\n\
      if only 2 points specified ) will then be normalised.\n\
\n\
for example: x=ginput([1 10]) \n\
   the first two clicks should correspond to x=1 and x=10 \n\
   subsequent clicks will then be normalized to graph units.  \n\
\n\
for example: [x,y]=ginput; \n\
   gives x and y in screen pixel units (upper left = 0,0 ) \n\
\n\
select points with button #1. Buttons 2 and 3 quit. ")
{
  XEvent event;
  XButtonEvent *e;
  Cursor  cursor;
  Display *dpy;
  int     xc[maxpoints],yc[maxpoints],nc=0;
  octave_value_list retval;

  int nargin = args.length();

  if (nargin > 1) {
    print_usage ("ginput");
    return retval;
  }
  else if (nargin == 1) {
    Matrix axis= args(0).matrix_value();

    nc= args(0).columns();
    
    if (nc==2 || nc==4) 
      octave_stdout << "First click on x-axis points " << 
                axis(0,0) << ", " << axis(0,1) <<"\n";
    if (nc==4) 
      octave_stdout << "Then click on y-axis points " << 
                axis(0,2) << ", " << axis(0,3) <<"\n";
    flush_octave_stdout ();
  }

  char *displayname = NULL;
  dpy = XOpenDisplay (displayname);

  if (!dpy) {
    fprintf(stderr,"GINPUT:  unable to open display %s\n",
                    XDisplayName(displayname));
    exit (1);
  }

  cursor = XCreateFontCursor(dpy, XC_crosshair);

  /* Grab the pointer using target cursor, letting it room all over */
  Window root = RootWindow(dpy,0);
  int done = XGrabPointer(dpy, root, False, ButtonPressMask,
         GrabModeSync, GrabModeAsync, root, cursor, CurrentTime);
  if (done != GrabSuccess) {
    fprintf(stderr,"GINPUT: Can't grab the mouse.\n");
    exit(1);
  };

  int m=0;
  do {
    XAllowEvents(dpy, SyncPointer, CurrentTime);
    XWindowEvent(dpy, root, ButtonPressMask, &event);

    e = (XButtonEvent *) &event;

    xc[m]= e->x_root;
    yc[m]= e->y_root;

/*
    printf("%d,%d,(%d,%d),B=%u,t=%lu\n",
         e->x, e->y, e->x_root, e->y_root, e->button, e->time);
*/
  } while (e->button == 1 && ++m < maxpoints);

  if (m < nc) {
    fprintf(stderr,"GINPUT: Not enough points selected.\n");
    exit(1);
  };

  double xb=0, xm=1, yb=0, ym=1;
  if (nc==2 || nc==4) {
    Matrix axis= args(0).matrix_value();

    xm= (axis(0,0)-axis(0,1)) / (xc[0]-xc[1]);
    xb= (xc[1]*axis(0,0)-xc[0]*axis(0,1)) / (xc[1]-xc[0]);

//  octave_stdout << "xm=" << xm << " xb=" << xb ;

    if (nc==4) {
      ym= (axis(0,2)-axis(0,3)) / (yc[2]-yc[3]);
      yb= (yc[3]*axis(0,2)-yc[2]*axis(0,3)) / (yc[3]-yc[2]);
    };
  };
  
  ColumnVector x(m-nc),y(m-nc);
  for(int i=nc; i<m; i++) {
    x(i-nc)= (double) xc[i]*xm + xb;
    y(i-nc)= (double) yc[i]*ym + yb;
  };

  XUngrabPointer(dpy, CurrentTime);      /* Done with pointer */
  XCloseDisplay (dpy);

  retval(0) = x;
  if (nargout == 2) 
      retval(1) = y;
  
  return retval;
}