Class Unistroke

java.lang.Object
  extended by Unistroke

public class Unistroke
extends java.lang.Object

A class for performing character recognition on unistrokes.

A "unistroke" is a set of x-y sample points created in a single gesture with a stylus or finger on a digitizing surface.

Applications using the Unistroke class generally need to instantiate only one Unistroke object. Thereafter, all processing, such as character recognition, loading custom dictionaries, and switching between the built-in and custom dictionaries, may be performed through this object via the fields and instance methods of the Unistroke class.

The Unistroke class includes three built-in dictionaries (graffiti, unistrokes, digits) and support for up to five custom dictionaries.

The process of recognition involves computing the "features" of a stroke and then comparing them with the features in the dictionary to find a match.

Dictionary Description

Each row in the dictionary contains thirteen (13) values delimited by spaces or commas. As well, a dictionary may include comment lines beginning with "#" (hash symbol), or blank lines. These are ignored.

The thirteen values consist of the recognized character(s) for the entry (symbol) followed by twelve stroke "features". These consist of four values representing the stroke's transition through "quadrants" of a bounding box (quadf, quads, quadsl, quadl), four values representing the cumulative distance of the stroke along the x and y axes (kxmin, kxmax, kymin, kymax), and four values representing the starting and terminating directions of the stroke along the x and y axes (startx, starty, stopx, stopy).

In calculating the features in a stroke, the sample points are first normalized to fit within a unit bounding box. The bounding box is divided into four quadrants, "0" at the top right, "1" at the lower right, "2" at the lower left, and "3" at the upper left:

Besides these four values, a dictionary entry may contain the value "4", implying "don't care". In this case, the recognizer will not check the corresponding quadrant feature in the current stroke.

The dictionary entries are described in greater detail below.

symbol is the string the recognizer returns if the features in the current stroke match the defined values in a particular row of the dictionary.

By convention, "=string" is used for strokes which are recognized, but for which no particular character is assigned by the recognizer. For these strokes, the application is expected to provide an appropriate interpretation. For example,

     =SW for a straight-line stroke in a south west direction
     =CR for a stroke intended to represent a carriage return
 
Since the recognizer returns a string, not a character, it is possible to define "shorthand" strokes — single strokes that return a complete word or phrase. These may be defined in the "home" dictionary, or in a dedicated mode-shift dictionary. A mode-shift dictionary is a dictionary invoked through a dedicate mode-shift stroke in the "home" dictionary (much like the "symbol shift" stroke in graffiti).

quadf is an integer representing the required first quadrant for the stroke.

quads is an integer representing the required second quadrant for the stroke.

quadsl is an integer representing the required second last quadrant for the stroke.

quadl is an integer representing the required last quadrant for the stroke.

Each stroke's "cumulative" distance features are calculated in the recognizer by summing the absolute distances between successive pairs of sample points along both the x and y axes.

The calculation is performed on the "normalized" sample points; that is, on the sample points after they are scaled to fit within a "unit bounding box" (width = 1, height = 1).

For example, a Graffiti "a", if entered perfectly, will have a cumulative x distance of 1 unit and a cumulative y distance of 2 units:

Similarly, a graffiti "z", if entered perfectly, will have a cumulative x distance of 3 units and a cumulative y distance of 1 unit:

Obviously, users to do not enter their strokes "perfectly". For a stroke to be recognized, the calculated cumulative distance features must fall within the minimum and maximum values (inclusive) in the stroke dictionary. These values may be specified as reals (e.g., 2.1).

Thus, the four cumulative distance values in the dictionary are defined as follows.

kxmin represents the required minimum cumulative x distance for the stroke

kxmax represents the required maximum cumulative x distance for the stroke

kymin represents the required minimum cumulative y distance for the stroke

kxmax represents the required maximum cumulative y distance for the stroke

The last four dictionary values represent the starting and terminating direction of the stroke. In the recognizer, these are computed on the first and last 25% of the samples. The computed value is either 0 or 1, where "0" implies motion to the left along the x axis or downward along the y axis, and "1" implies motion to the right along the x axis or upward along the y axis.

For example, the stroke for a graffiti "a" should begin with motion "to the right" along the x axis and motion "up" along the y axis. It should terminate with motion "to the right" along the x axis and motion "down" along the y axis:

Depending on the desired stroke shape, the corresponding dictionary entries should be either 0 or 1. As well, "4" may appear in the dictionary as a "don't care" condition. In this case, the recognizer does not check the stroke's corresponding feature.

The four direction values are as follows.

startx is an integer representing the required starting x direction for the stroke

starty is an integer representing the required starting y direction for the stroke

stopx is an integer representing the required terminating x direction for the stroke

stopy is an integer representing the required terminating y direction for the stroke

Author:
Scott MacKenzie, 2001-2011

Field Summary
 StrokeDef[] activeDictionary
          Provides access to the currently active stroke dictionary.
static int CUSTOM1
          A constant identifying a custom stroke dictionary.
static int CUSTOM2
          A constant identifying a custom stroke dictionary.
static int CUSTOM3
          A constant identifying a custom stroke dictionary.
static int CUSTOM4
          A constant identifying a custom stroke dictionary.
static int CUSTOM5
          A constant identifying a custom stroke dictionary.
static int DIGITS
          A constant identifying the built-in "digits" stroke dictionary.
static int GRAFFITI
          A constant identifying the built-in "graffiti" stroke dictionary.
static java.util.Vector<java.lang.String> matchString
           
static int UNISTROKES
          A constant identifying the built-in "unistrokes" stroke dictionary.
 
Method Summary
 void flipX()
          Flip the orientation of the x coordinates.
 void flipY()
          Flip the orientation of the y coordinates.
 java.lang.String getFeatures(int[] x, int[] y)
          Calculate and return the features of a unistroke.
 java.lang.String getFeatures(int[] x, int[] y, int length)
          Calculate and return the features of a unistroke (3-arg version)
 boolean loadDictionary(java.lang.String s, int n)
          Load a custom dictionary from a disk file.
static void main(java.lang.String[] args)
          Test the Unistroke class.
 java.lang.String recognize(int[] x, int[] y)
          Perform unistroke character recognition.
 java.lang.String recognize(int[] x, int[] y, int length)
          Perform unistroke character recognition (3-arg version).
 java.lang.String recognize(Point[] p, int length)
          Perform unistroke character recognition (Point class version).
 void setAspectRatio(double d)
          Change the aspect ratio for horizontal or vertical strokes.
 void setDictionary(int d)
          Set or change the active dictionary.
 void setTapThreshhold(int n)
          Change the threshhold setting for a tap.
 void setUndefined(java.lang.String s)
          Change the return string for an undefined stroke.
 
Methods inherited from class java.lang.Object
equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

CUSTOM1

public static final int CUSTOM1
A constant identifying a custom stroke dictionary.

The Unistroke class supports up to five custom dictionaries. They may be changed on-the-fly using the setDictionary() method with this field as an argument.

See Also:
setDictionary(int), loadDictionary(java.lang.String, int), Constant Field Values

CUSTOM2

public static final int CUSTOM2
A constant identifying a custom stroke dictionary.

The Unistroke class supports up to five custom dictionaries. They may be changed on-the-fly using the setDictionary() method with this field as an argument.

See Also:
setDictionary(int), loadDictionary(java.lang.String, int), Constant Field Values

CUSTOM3

public static final int CUSTOM3
A constant identifying a custom stroke dictionary.

The Unistroke class supports up to five custom dictionaries. They may be changed on-the-fly using the setDictionary() method with this field as an argument.

See Also:
setDictionary(int), loadDictionary(java.lang.String, int), Constant Field Values

CUSTOM4

public static final int CUSTOM4
A constant identifying a custom stroke dictionary.

The Unistroke class supports up to five custom dictionaries. They may be changed on-the-fly using the setDictionary() method with this field as an argument.

See Also:
setDictionary(int), loadDictionary(java.lang.String, int), Constant Field Values

CUSTOM5

public static final int CUSTOM5
A constant identifying a custom stroke dictionary.

The Unistroke class supports up to five custom dictionaries. They may be changed on-the-fly using the setDictionary() method with this field as an argument.

See Also:
setDictionary(int), loadDictionary(java.lang.String, int), Constant Field Values

GRAFFITI

public static final int GRAFFITI
A constant identifying the built-in "graffiti" stroke dictionary.

Use as an argument to the setDictionary() method.

The graffiti alphabet is shown below:

See Also:
setDictionary(int), Constant Field Values

UNISTROKES

public static final int UNISTROKES
A constant identifying the built-in "unistrokes" stroke dictionary.

Use as an argument to the setDictionary() method.

Note: "unistrokes" is this sense implies the stroke alphabet presented in the paper "Touch typing with a stylus" by D. Goldberg and C. Richardson, published in the Proceedings of INTERCHI '93, pp. 80-87. This is the original "unistrokes" paper.

The unistrokes alphabet is shown below:

See Also:
setDictionary(int), Constant Field Values

DIGITS

public static final int DIGITS
A constant identifying the built-in "digits" stroke dictionary.

Use as an argument to the setDictionary() method.

The digits alphabet is shown below:

See Also:
setDictionary(int), Constant Field Values

activeDictionary

public StrokeDef[] activeDictionary
Provides access to the currently active stroke dictionary.

A variety of debugging and advanced programming services are available through this public variable. Given a Unistroke object u, the number of entries in the currently active dictionary is

     u.activeDictionary.length
 
Each entry in the currently active dictionary may be retrieved. For example
     for (int i = 0; i < u.activeDictionary.length; ++i)
        System.out.println(u.activeDictionary[i]);
 
outputs the entire dictionary to the console.

Each row in the dictionary is returned as a string containing thirteen comma-delimited values. For example, the entry for the letter "a" in the built-in graffiti dictionary appears as follows:

     a, 2, 3, 0, 1, 0.9, 1.2, 1.5, 2.0, 4, 1, 4, 0
 
where
     symbol = a
     quadf  = 2
     quads  = 3
     quadsl = 0
     quadl  = 1
     kxmin  = 0.9
     kxmax  = 1.2
     kymin  = 1.5
     kymax  = 2.0
     startx = 4
     starty = 1
     stopx  = 4
     stopy  = 0
 
See the description for the loadDictionary() method for further discussion on each entry in the dictionary.

See Also:
loadDictionary(java.lang.String, int)

matchString

public static java.util.Vector<java.lang.String> matchString
Method Detail

loadDictionary

public boolean loadDictionary(java.lang.String s,
                              int n)
Load a custom dictionary from a disk file. After loading, the custom dictionary becomes the currently active dictionary.

Parameters:
s - the name of the disk file containing the stroke definitions.
n - an integer representing the dictionary (e.g., Unistroke.CUSTOM1). This argument is used later with the setDictionary() method to switch from one dictionary to another.
Returns:
true if the load was successful, false otherwise.

setTapThreshhold

public void setTapThreshhold(int n)
Change the threshhold setting for a tap.

The definition of a stylus "tap" is any stroke with less than a certain threshhold of samples. The default threshhold is 5.

The recognize() method returns "=TAP" for any stroke meeting this criterion.

Parameters:
n - an integer representing the number of samples below which a stroke is considered a tap.

setUndefined

public void setUndefined(java.lang.String s)
Change the return string for an undefined stroke.

By default, the recognizer returns the string "#" (hash symbol) for unrecognized strokes.

Parameters:
s - the new return string for unrecognized strokes

setAspectRatio

public void setAspectRatio(double d)
Change the aspect ratio for horizontal or vertical strokes. The default aspect ratio is 0.2.

Parameters:
d - a double representing the new aspect ratio.


Discussion:

Horizontal or vertical strokes pose a special problem for the recognizer because the stroke shape is grossly distorted when the sample points are normalized. To accommodate this, a special test is performed on the unnormalized sample points to determine if a stroke is horizontal or vertical.

A stroke is recognized as horizontal or vertical if the aspect ratio — the thickness-to-length ratio — of the unnormalized sample points is less than a certain threshhold. The default is 0.2.

A stroke meeting the criteron above is explicitly assigned the following values for its cumulative x distance and cumulative y distance:

     stroke   kx   ky
     ------  ---  ---
     NORTH   1.0  0.0
     SOUTH   1.0  0.0
     EAST    0.0  1.0
     WEST    0.0  1.0
 

flipY

public void flipY()
Flip the orientation of the y coordinates.

The sample points passed to the recognize() method are assumed to be consistent with Java's AWT coordinate system: namely, x coordinates increase moving to the right across the display, and y coordinates increase moving down the display. The flipY() method can be used to reverse the orientation of the y coordinates, if necessary.

This method needs to be called once only, after instantiating the Unistroke object. If the method is called a a second time, the original orientation is restored.


flipX

public void flipX()
Flip the orientation of the x coordinates. See the flipY() method for discussion.


setDictionary

public void setDictionary(int d)
Set or change the active dictionary. For example,

     setDictionary(Unistroke.DIGITS);
 
changes the currently active dictionary to the digits dictionary.

Parameters:
d - an integer representing a dictionary.

The following dictionaries are defined:

 Unistroke.GRAFFITI   - built-in graffiti dictionary (default)
 Unistroke.UNISTROKES - built-in unistrokes dictionary
 Unistroke.DIGITS     - build-in digits dictionary
 Unistroke.CUSTOM1    - user-provided custom dictionary #1
 Unistroke.CUSTOM2    - user-provided custom dictionary #2
 Unistroke.CUSTOM3    - user-provided custom dictionary #3 
 Unistroke.CUSTOM4    - user-provided custom dictionary #4
 Unistroke.CUSTOM5    - user-provided custom dictionary #5
 

recognize

public java.lang.String recognize(int[] x,
                                  int[] y)
Perform unistroke character recognition. This is the basic method to convert a series of x-y sample points to a character. The returned string is one of the following:

  1. a string containing the entry in the dictionary corresponding to the stroke, if recognition was successful,
  2. the string "#" (hash symbol), if a match for the stroke was not found, or
  3. the string "=TAP" if the stroke meets the criterion for a "tap" (i.e., it contains less than a certain threshhold of samples).

Parameters:
x - an integer array of x sample points.
y - an integer array of y sample points.
Returns:
a string representation of the recognized unistroke character,


recognize

public java.lang.String recognize(int[] x,
                                  int[] y,
                                  int length)
Perform unistroke character recognition (3-arg version).

Parameters:
x - an integer array of x sample points.
y - an integer array of y sample points.
length - an integer representing the number of elements in the arrays to process
Returns:
a string representation of the recognized unistroke character,


recognize

public java.lang.String recognize(Point[] p,
                                  int length)
Perform unistroke character recognition (Point class version).

Parameters:
p - an array of Point objects.
length - an integer representing the number of elements in the Point array to process
Returns:
a string representation of the recognized unistroke character,


getFeatures

public java.lang.String getFeatures(int[] x,
                                    int[] y,
                                    int length)
Calculate and return the features of a unistroke (3-arg version)


getFeatures

public java.lang.String getFeatures(int[] x,
                                    int[] y)
Calculate and return the features of a unistroke. The returned string is one of the following:

  1. a string containing a set of ten comma-delimited features for the passed unistroke, or
  2. the string "=TAP" for a stylus "tap".

For example, the following could be the returned string for a unistroke resembling a graffiti "a":

     2, 3, 0, 1, 1.010, 1.857, 1, 1, 1, 0
 
The ten values above represent the following unistroke features:

     quadf  = 2
     quads  = 3
     quadsl = 0
     quadl  = 1
     kx     = 1.010
     ky     = 1.855
     startx = 1
     starty = 1
     stopx  = 1
     stopy  = 0
 

Parameters:
x - an integer array of x sample points.
y - an integer array of y sample points.
Returns:
a string containing the features of the passed unistroke, or "=TAP" for a unistroke representing a stylus tap.

main

public static void main(java.lang.String[] args)
                 throws java.io.IOException
Test the Unistroke class.

Throws:
java.io.IOException