view plugins/gestures/stroke.c @ 4687:283fb289c510

[gaim-migrate @ 4998] This is a new buddy list. Lots of things about it just Don't Work. I probably already know about those things, and you'd just be wasting my time in submitting a bug report about it. I decided that instead of getting it to all work perfectly before committing, that I'd get it in cvs, and slowly fix it with regular commits. That way, it's easier to keep track of things, and other developers can help. Plus, I'm getting pissed off at the buddy list and want it to die. It's kinda boring, and doing nothing but the buddy list for such a long time has just gotten me very bitter. After 0.60 is released later this week, Gaim will resume being fun. This week is going to be very stressful, though, I'm sure. Things you ought to know about this buddy list: - It crashes - It leaks - There's no way to edit the buddy list, or access offline buddies - Most of the menus and buttons and whatnot just plain ol' don't work. - Status icons are only implemented for AIM. That's mostly just because I'm lazy. As such, you may want to be wary of updating this. If you do decide to update this, you may want to learn "cvs update -D yesterday" as well :) All the art there is just placeholder art. You probably won't really have as many problems as it sounds like you will from reading this. This message is extra-negative to stress that I don't want to be bothered with complaints about something not working about it :). I'll repeat: If something doesn't work, I probably already know about it. If you want to actually help with something, I'd be delighted to have it. IM me. -s. committer: Tailor Script <tailor@pidgin.im>
author Sean Egan <seanegan@gmail.com>
date Mon, 10 Mar 2003 05:30:31 +0000
parents 16540914c963
children 5239a3b4ab33
line wrap: on
line source

/*
   libgstroke - a GNOME stroke interface library
   Copyright (c) 1996,1997,1998,1999,2000,2001  Mark F. Willey, ETLA Technical

   See the file COPYING for distribution information.

   This file contains the stroke recognition algorithm.
*/

#include "config.h"

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <glib.h>
#include <gtk/gtk.h>
#include "gstroke.h"
#include "gstroke-internal.h"


void
_gstroke_init (struct gstroke_metrics *metrics)
{
  if (metrics->pointList != NULL) {
    /* FIXME: does this free the data too?*/
    g_slist_free (metrics->pointList);
    metrics->pointList = NULL;
    metrics->point_count = 0;
  }
}

/* figure out which bin the point falls in */
static gint
_gstroke_bin (p_point point_p, gint bound_x_1, gint bound_x_2,
	    gint bound_y_1, gint bound_y_2)
{

  gint bin_num = 1;

  if (point_p->x > bound_x_1) bin_num += 1;
  if (point_p->x > bound_x_2) bin_num += 1;
  if (point_p->y > bound_y_1) bin_num += 3;
  if (point_p->y > bound_y_2) bin_num += 3;

  return bin_num;
}

gint
_gstroke_trans (gchar *sequence, struct gstroke_metrics *metrics)
{
  GSList *crt_elem;
  /* number of bins recorded in the stroke */
  guint sequence_count = 0;

  /* points-->sequence translation scratch variables */
  gint prev_bin = 0;
  gint current_bin = 0;
  gint bin_count = 0;

  /* flag indicating the start of a stroke - always count it in the sequence */
  gint first_bin = TRUE;

  /* bin boundary and size variables */
  gint delta_x, delta_y;
  gint bound_x_1, bound_x_2;
  gint bound_y_1, bound_y_2;


  /* determine size of grid */
  delta_x = metrics->max_x - metrics->min_x;
  delta_y = metrics->max_y - metrics->min_y;

  /* calculate bin boundary positions */
  bound_x_1 = metrics->min_x + (delta_x / 3);
  bound_x_2 = metrics->min_x + 2 * (delta_x / 3);

  bound_y_1 = metrics->min_y + (delta_y / 3);
  bound_y_2 = metrics->min_y + 2 * (delta_y / 3);

  if (delta_x > GSTROKE_SCALE_RATIO * delta_y) {
    bound_y_1 = (metrics->max_y + metrics->min_y - delta_x) / 2 + (delta_x / 3);
    bound_y_2 = (metrics->max_y + metrics->min_y - delta_x) / 2 + 2 * (delta_x / 3);
  } else if (delta_y > GSTROKE_SCALE_RATIO * delta_x) {
    bound_x_1 = (metrics->max_x + metrics->min_x - delta_y) / 2 + (delta_y / 3);
    bound_x_2 = (metrics->max_x + metrics->min_x - delta_y) / 2 + 2 * (delta_y / 3);
  }

#if 0
  printf ("DEBUG:: point count: %d\n", metrics->point_count);
  printf ("DEBUG:: metrics->min_x: %d\n", metrics->min_x);
  printf ("DEBUG:: metrics->max_x: %d\n", metrics->max_x);
  printf ("DEBUG:: metrics->min_y: %d\n", metrics->min_y);
  printf ("DEBUG:: metrics->max_y: %d\n", metrics->max_y);
  printf ("DEBUG:: delta_x: %d\n", delta_x);
  printf ("DEBUG:: delta_y: %d\n", delta_y);
  printf ("DEBUG:: bound_x_1: %d\n", bound_x_1);
  printf ("DEBUG:: bound_x_2: %d\n", bound_x_2);
  printf ("DEBUG:: bound_y_1: %d\n", bound_y_1);
  printf ("DEBUG:: bound_y_2: %d\n", bound_y_2);
#endif

  /*
    build string by placing points in bins, collapsing bins and
    discarding those with too few points...  */

  crt_elem = metrics->pointList;
  while (crt_elem != NULL)
    {
      /* figure out which bin the point falls in */

      /*printf ("X = %d Y = %d\n", ((p_point)crt_elem->data)->x,
	((p_point)crt_elem->data)->y); */


      current_bin = _gstroke_bin ((p_point)crt_elem->data, bound_x_1,
                                 bound_x_2, bound_y_1, bound_y_2);

      /* if this is the first point, consider it the previous bin, too. */
      if (prev_bin == 0)
	prev_bin = current_bin;

      /*printf ("DEBUG:: current bin: %d x=%d y = %d\n", current_bin,
	      ((p_point)crt_elem->data)->x,
	      ((p_point)crt_elem->data)->y); */

      if (prev_bin == current_bin)
	bin_count++;
      else {
	/* we are moving to a new bin -- consider adding to the sequence */
	if ((bin_count > (metrics->point_count * GSTROKE_BIN_COUNT_PERCENT))
	    || (first_bin == TRUE)) {

	  //gchar val = '0' + prev_bin;
	  //printf ("%c", val);fflush (stdout);
	  //g_string_append (&sequence, &val);

	  first_bin = FALSE;
	  sequence[sequence_count++] = '0' + prev_bin;
	  /*  printf ("DEBUG:: adding sequence: %d\n", prev_bin); */

	}

	/* restart counting points in the new bin */
	bin_count=0;
	prev_bin = current_bin;
      }

      /* move to next point, freeing current point from list */

      free (crt_elem->data);
      crt_elem = g_slist_next (crt_elem);
    }
  /* add the last run of points to the sequence */
  sequence[sequence_count++] = '0' + current_bin;
  /*  printf ("DEBUG:: adding final sequence: %d\n", current_bin);  */

  _gstroke_init (metrics);

  {
    // FIXME: get rid of this block
    //gchar val = '0' + current_bin;
    //printf ("%c\n", val);fflush (stdout);
    //g_string_append (&sequence,  '\0');
    sequence[sequence_count] = '\0';
  }

  return TRUE;
}

/* my plan is to make a stroke training program where you can enter all of
the variations of slop that map to a canonical set of strokes.  When the
application calls gstroke_canonical, it gets one of the recognized strokes,
or "", if it's not a recognized variation.  I will probably use a hash
table.  Right now, it just passes the values through to gstroke_trans */
gint
_gstroke_canonical (gchar *sequence, struct gstroke_metrics *metrics)
{
  return _gstroke_trans (sequence, metrics);
}


void
_gstroke_record (gint x, gint y, struct gstroke_metrics *metrics)
{
  p_point new_point_p;
  gint delx, dely;
  float ix, iy;

#if 0
  printf ("%d:%d ", x, y); fflush (stdout);
#endif

  if (metrics->point_count < GSTROKE_MAX_POINTS) {
    new_point_p = (p_point) g_malloc (sizeof (struct s_point));

    if (metrics->pointList == NULL) {

      /* first point in list - initialize metrics */
      metrics->min_x = 10000;
      metrics->min_y = 10000;
      metrics->max_x = -1;
      metrics->max_y = -1;

      metrics->pointList = (GSList*) g_malloc (sizeof (GSList));

      metrics->pointList->data = new_point_p;
      metrics->pointList->next = NULL;
      metrics->point_count = 0;

    } else {

#define LAST_POINT ((p_point)(g_slist_last (metrics->pointList)->data))

      /* interpolate between last and current point */
      delx = x - LAST_POINT->x;
      dely = y - LAST_POINT->y;

      if (abs(delx) > abs(dely)) {  /* step by the greatest delta direction */
	iy = LAST_POINT->y;

	/* go from the last point to the current, whatever direction it may be */
	for (ix = LAST_POINT->x; (delx > 0) ? (ix < x) : (ix > x); ix += (delx > 0) ? 1 : -1) {

	  /* step the other axis by the correct increment */
	  iy += fabs(((float) dely / (float) delx)) * (float) ((dely < 0) ? -1.0 : 1.0);

	  /* add the interpolated point */
	  new_point_p->x = ix;
	  new_point_p->y = iy;
	  g_slist_append (metrics->pointList, new_point_p);

	  /* update metrics */
	  if (((gint) ix) < metrics->min_x) metrics->min_x = (gint) ix;
	  if (((gint) ix) > metrics->max_x) metrics->max_x = (gint) ix;
	  if (((gint) iy) < metrics->min_y) metrics->min_y = (gint) iy;
	  if (((gint) iy) > metrics->max_y) metrics->max_y = (gint) iy;
	  metrics->point_count++;

	  new_point_p = (p_point) malloc (sizeof(struct s_point));
	}
      } else {  /* same thing, but for dely larger than delx case... */
	ix = LAST_POINT->x;

	/* go from the last point to the current, whatever direction it may be
	 */
	for (iy = LAST_POINT->y; (dely > 0) ? (iy < y) : (iy > y); iy += (dely > 0) ? 1 : -1) {

	  /* step the other axis by the correct increment */
	  ix += fabs(((float) delx / (float) dely)) * (float) ((delx < 0) ? -1.0 : 1.0);

	  /* add the interpolated point */
	  new_point_p->y = iy;
	  new_point_p->x = ix;
	  g_slist_append(metrics->pointList, new_point_p);

	  /* update metrics */
	  if (((gint) ix) < metrics->min_x) metrics->min_x = (gint) ix;
	  if (((gint) ix) > metrics->max_x) metrics->max_x = (gint) ix;
	  if (((gint) iy) < metrics->min_y) metrics->min_y = (gint) iy;
	  if (((gint) iy) > metrics->max_y) metrics->max_y = (gint) iy;
	  metrics->point_count++;

	  new_point_p = (p_point) malloc (sizeof(struct s_point));
	}
      }

      /* add the sampled point */
      g_slist_append(metrics->pointList, new_point_p);
    }

    /* record the sampled point values */
    new_point_p->x = x;
    new_point_p->y = y;

#if 0
    {
      GSList *crt = metrics->pointList;
      printf ("Record ");
      while (crt != NULL)
	{
	  printf ("(%d,%d)", ((p_point)crt->data)->x, ((p_point)crt->data)->y);
	  crt = g_slist_next (crt);
	}
      printf ("\n");
    }
#endif
  }
}