/*
 * 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.
 * 
 * Copyright (C) 1997 Andy Adler <adler@ncf.ca>
 * 
 * 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.
 */

/*
 * Copyright (C) 2001 Laurent Mazet <mazet@crm.mot.com>
 *
 * Fix error handler to avoid octave core-dump.
 * Change to avoid the input limit.
 * Minimize the number of cliks for full x-y axis definitions.
 * Make the code a bit less ugly.
 */

/*
 * Andy Adler <adler@ncf.ca> 2002
 *
 * Modifications to run under windoze
 * $Id: grab.cc,v 1.6 2005/05/25 03:43:38 pkienzle Exp $
 */



#include <octave/oct.h>
#include <iostream>
#include "sysdep.h"
#include <octave/pager.h>

int grab_win32_getmousepos ( int * xpt, int * ypt );

#define maxpoints 20

DEFUN_DLD (grab, args, nargout,
           "[...] = grab (...)\n"
           "\n"
           "grab: grab positions of landmarks on the screen\n"
           " \n"
           "[x,y]= grab(axis)\n"
           " x -> x coordinates of the points\n"
           " y -> y coordinates of the points\n"
           "\n"
           " axis -> if specified then the first 2 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=grab([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]=grab; \n"
           "   gives x and y in screen pixel units (upper left = 0,0 ) \n"
           "\n"
           "select points by positioning the cursor over the points\n"
           "and clicking <SPACE>. 'q' or <ESC> quits")
{
  ColumnVector axis;
  ColumnVector xaxis(2);
  ColumnVector yaxis(2);
  int nc;
  
  switch (args.length()) {
    case 0:
      nc = 0;
      break;
    case 1:
        { // we need to do this to allow arbitrary orientation
           ColumnVector tmp( args(0).vector_value() );
           if (error_state) return octave_value_list();
           axis = tmp;
        }
        nc = axis.length ();
        if ((nc == 2) || (nc == 4))
          break;
    default:
      print_usage ("grab");
      return octave_value_list();
  }
    
  switch (nc) {
    case 2:
      octave_stdout << "First click on x-axis " << axis(0) << std::endl;
      octave_stdout << "Then click on x-axis " << axis(1) << std::endl;
      flush_octave_stdout();
      break;
    case 4:
      octave_stdout << "First click on point "
                    << "(" << axis(0) << "," << axis(2) << ")" << std::endl;
      octave_stdout << "Then click on point "
                    << "(" << axis(1) << "," << axis(3) << ")" << std::endl;
      flush_octave_stdout();
      break;
  }


  if (nc != 0) {
    int axispoints=0;
    while ( axispoints < 2 ) {
      int ch;
      int xpt; int ypt;

      ch= octave_kbhit( 0 );
      grab_win32_getmousepos ( & xpt, & ypt );

      if (ch == ' ') {
        xaxis (axispoints) = (double)xpt;
        yaxis (axispoints) = (double)ypt;
        axispoints++;
      }

    }
  }


  /* Wait for a click */
  MArray<int> xc(maxpoints);
  MArray<int> yc(maxpoints);

  int nb_elements = 0;
  while (1) {
    int ch;
    int xpt, ypt;

    ch= octave_kbhit( 0 );
    grab_win32_getmousepos ( & xpt, & ypt );

    if (ch == ' ') {
      xc (nb_elements) = xpt;
      yc (nb_elements) = ypt;
      nb_elements++;
    }
    else break;
    
    if (nb_elements == xc.length()) {
      xc.resize (xc.length()+maxpoints);
      yc.resize (yc.length()+maxpoints);
    }
  }

  
  double xb=0, xm=1, yb=0, ym=1;
  if ((nc == 2) || (nc == 4)) {
    double xdiff = xaxis(1) - xaxis(0);
    xm = -(axis(0)-axis(1)) / xdiff;
    xb = (xaxis(1)*axis(0)-xaxis(0)*axis(1)) / xdiff;
    if (nc == 4) {
      double ydiff = yaxis(1) - yaxis(0);
      ym = -(axis(2)-axis(3)) / ydiff;
      yb = (yaxis(1)*axis(2)-yaxis(0)*axis(3)) / ydiff;
    }
  }

  ColumnVector x(nb_elements), y(nb_elements);
  for(int i=0; i<nb_elements; i++) {
    x(i) = xc(i)*xm + xb;
    y(i) = yc(i)*ym + yb;
  }

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


syntax highlighted by Code2HTML, v. 0.9.1