public class Unistroke
extends java.lang.Object
A Unistroke is a set of x-y sample points created in a single gesture with a stylus or finger on a digitizing surface. The sample points map out the shape of the gesture. The gestures represent characters, symbols, or commands. A gesture is also called a stroke.
The idea for Unistrokes as a handwriting method for computers originated in 1993 in the paper Touch Typing with a Stylus by D. Goldberg and C. Richardson, There is also a patent for Unistrokes, naming Goldberg as the inventor. The patent issued in January 1997 and is assigned to Xerox Corporation.
The most widely-known commercial example of Unistrokes is the Graffiti text entry method used on the Palm Pilot personal digital assistant (PDA), first introduced in 1997. The paper The Immediate Usability of Graffiti provides discussion and historical context for both Unistrokes and Graffiti. The paper also presents an empirical evaluation of Graffiti.
Applications using the Unistroke
class generally need to instantiate only one Unistroke
object. Thereafter, all processing, such as stroke recognition, loading customDictionary dictionaries, and switching
between the built-in and customDictionary dictionaries, is performed through the fields and instance methods of the
Unistroke
class.
The Unistroke
class includes three built-in dictionaries (GRAFFITI, UNISTROKES, DIGITS
) and
support for one customDictionary dictionary.
Recognition involves computing the features of an inputted stroke and then comparing the features against those in the dictionary to find a match.
Each row in the dictionary contains thirteen (13) values delimited by spaces or commas. As well, a dictionary may
include comment lines beginning with "#
" or blank lines. These are ignored.
The thirteen values consist of a recognized string for the stroke (symbol
) followed by twelve stroke
features. The features consist of four values representing the stroke's transition through quadrants of a bounding
box (quadFirst, quadSecond, quadPenultimate, quadLast
), 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 representing a quadrant, 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
- the string the recognizer returns if the features in the current stroke match the defined values in a particular row of the dictionary.
In most cases, the returned string is a single character representing the inputted stroke, such as "a", "b", etc.
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,
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 or added to the home dictionary or in a dedicated mode-shift dictionary. A mode-shift dictionary is a dictionary invoked through a dedicated mode-shift stroke in the home dictionary (much like the "symbol shift" stroke in Graffiti as implemented on the Palm Pilot).=SW
for a straight-line stroke in a south-west directionThe four quadrant features characterize the beginning and ending of a stroke in terms of the expected quadrants. For example, the stroke for a Graffiti "b" is expected to begin in quadrant 2, then transition into quadrant 3. The stroke ends in quadrant 2, having transitioned from quadrant 1:
The quadrant features are thus defined:
quadFirst
- an integer representing the required first quadrant for the stroke.
quadSecond
- an integer representing the required second quadrant for the stroke.
quadPenultimate
- an integer representing the required penultimate (second last) quadrant for the stroke.
quadLast
- an integer representing the required last quadrant for the stroke.
The four cumulative distance features are calculated in the recognizer by summing the absolute distances between successive pairs of sample points along 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 the 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 are specified as reals (e.g., 2.14).
Thus, the four cumulative distance values in the dictionary are defined as follows.
kxmin
- the minimum cumulative x distance for the stroke
kxmax
- the maximum cumulative x distance for the stroke
kymin
- the minimum cumulative y distance for the stroke
kxmax
- the 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
- an integer representing the required starting x direction for the stroke
starty
- an integer representing the required starting y direction for the stroke
stopx
- an integer representing the required terminating x direction for the stroke
stopy
- an integer representing the required terminating y direction for the stroke
Modifier and Type | Field and Description |
---|---|
ca.yorku.cse.mack.graffiti.StrokeDef[] |
activeDictionary
Provides access to the currently active stroke dictionary.
|
static java.util.ArrayList<java.lang.String> |
dictionaryMatches |
static int |
DIGITS
A constant identifying the built-in stroke dictionary for digits.
|
static int |
GRAFFITI
A constant identifying the built-in Graffiti stroke dictionary.
|
static int |
UNISTROKES
A constant identifying the built-in Unistrokes stroke dictionary.
|
static java.lang.String |
UNRECOGNIZED_STROKE |
Modifier and Type | Method and Description |
---|---|
java.lang.String |
recognize(android.graphics.Point[] p,
int length)
Perform handwriting recognition (
Point class version). |
void |
setDictionary(int d)
Set or change the active dictionary.
|
public static final java.lang.String UNRECOGNIZED_STROKE
public static final int GRAFFITI
Use as an argument to the setDictionary()
method.
The Graffiti alphabet is shown below:
The stroke shapes above do not exactly match those in the original Graffiti alphabet. Slight modifications have been introduced to improve recognition.
A few entries above (e.g., Caps) include two strokes. The interpretation is for a mode shift, which must be
implemented and managed by the application using the Unistroke
class.
setDictionary(int)
,
Constant Field Valuespublic static final int UNISTROKES
Use as an argument to the setDictionary()
method.
The Unistrokes alphabet is shown below:
setDictionary(int)
,
Constant Field Valuespublic static final int DIGITS
Use as an argument to the setDictionary()
method.
The digit strokes are is shown below:
setDictionary(int)
,
Constant Field Valuespublic static java.util.ArrayList<java.lang.String> dictionaryMatches
public ca.yorku.cse.mack.graffiti.StrokeDef[] activeDictionary
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.lengthEach 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, 0where
symbol = a quadFirst = 2 quadSecond = 3 quadsPenultimate = 0 quadLast = 1 kxmin = 0.9 kxmax = 1.2 kymin = 1.5 kymax = 2.0 startx = 4 starty = 1 stopx = 4 stopy = 0See the description for the
loadDictionary()
method for further discussion on each entry in the
dictionary.public void setDictionary(int d)
setDictionary(Unistroke.DIGITS);changes the currently active dictionary to the digits dictionary.
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.CUSTOM
- user-provided custom dictionary public java.lang.String recognize(android.graphics.Point[] p, int length)
Point
class version).p
- an array of Point
objects.length
- an integer representing the number of elements in the Point
array to process