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.
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.
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 returnSince 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
Modifier and Type | Field and Description |
---|---|
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.
|
Modifier and Type | Method and Description |
---|---|
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(java.awt.Point[] p)
Perform unistroke character recognition (Point class version).
|
java.lang.String |
recognize(java.awt.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.
|
public static final int CUSTOM1
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.
public static final int CUSTOM2
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.
public static final int CUSTOM3
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.
public static final int CUSTOM4
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.
public static final int CUSTOM5
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.
public static final int GRAFFITI
Use as an argument to the setDictionary()
method.
The graffiti alphabet is shown below:
setDictionary(int)
,
Constant Field Valuespublic static final int UNISTROKES
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:
setDictionary(int)
,
Constant Field Valuespublic static final int DIGITS
Use as an argument to the setDictionary()
method.
The digits alphabet is shown below:
setDictionary(int)
,
Constant Field Valuespublic 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 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 = 0See the description for the
loadDictionary()
method for further discussion on each entry in the
dictionary.loadDictionary(java.lang.String, int)
public static java.util.Vector<java.lang.String> matchString
public boolean loadDictionary(java.lang.String s, int n)
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.true
if the load was successful, false
otherwise.public void setTapThreshhold(int n)
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.
n
- an integer representing the number of samples below which a stroke is considered a tap.public void setUndefined(java.lang.String s)
By default, the recognizer returns the string "#
" (hash symbol) for unrecognized strokes.
s
- the new return string for unrecognized strokespublic void setAspectRatio(double d)
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
public void flipY()
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.
public void flipX()
flipY()
method for discussion.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.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
public java.lang.String recognize(int[] x, int[] y)
#
" (hash symbol), if a match for the stroke was not found, or
=TAP
" if the stroke meets the criterion for a "tap" (i.e., it contains less than a
certain threshhold of samples).
x
- an integer array of x sample points.y
- an integer array of y sample points.public java.lang.String recognize(int[] x, int[] y, int length)
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 processpublic java.lang.String recognize(java.awt.Point[] p, int length)
p
- an array of Point objects.length
- an integer representing the number of elements in the Point array to processpublic java.lang.String recognize(java.awt.Point[] p)
p
- an array of Point objects.public java.lang.String getFeatures(int[] x, int[] y, int length)
public java.lang.String getFeatures(int[] x, int[] y)
=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, 0The 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
x
- an integer array of x sample points.y
- an integer array of y sample points.=TAP
" for a unistroke
representing a stylus tap.public static void main(java.lang.String[] args) throws java.io.IOException
Unistroke
class.java.io.IOException