Penlets.com provides resources for users and developers of the Pulse smart pen from LiveScribe.
Subscribe: RSS Feed - Developers Group
Tutorial
Capturing Drawn Shapes
Tutorial by Robert HansonPage 1 » Page 2
Capturing Strokes with StrokeListener
So far we have a penlet that asks the user to draw a circle. When the
user does this it will trigger the calling of a
strokeCreated
method that is defined by the
StrokeListener
interface
/* ***********************************************
*
* StrokeListener interface methods.
*
*********************************************** */
/* [1] */
private Polygon targetArea;
public void strokeCreated (long time, Region region, PageInstance pageInstance)
{
/* [2] */
if (targetArea == null) {
/* [3] */
StrokeStorage strokeStorage = new StrokeStorage(pageInstance);
Stroke stroke = strokeStorage.getStroke(time);
/* [4] */
int v = stroke.getNumberofVertices();
targetArea = new Polygon(v);
/* [5] */
for (int i = 0; i < v; i++) {
targetArea.setXY(i, stroke.getX(i), stroke.getY(i));
}
/* [6] */
this.label.draw("Touch the pen to the paper", true);
}
}
Going back to what our penlet needs to do, recall that the user only gets to draw one circle then we change the behavior. For this we need two things; we need someplace to store the stroke data, and we need some flag to only grab the first stroke.
For the first part we will use a
Polygon
object to store the circle data, in a variable named
targetArea
[1]. The
Polygon
class is a subclass of the abstract
Shape class
. The Penlet SDK comes with seven different shapes, listed below
along with what they represent.
| Point | Used to store a single x,y coordinate. Has a utility method to calculate the distance between this point and some other point. |
| LineSegment | Represents a line between two points. |
| PolyLine | A line with any number of points. |
| Stroke | Similar to a PolyLine, except that it keeps track of the time. Has two methods to help determine when a particular part of the stoke was created. |
| Ellipse | Holds a center-point along with width and height. It does not allow for a rotation value to be stored. |
| Rectangle | Stores the upper-left coordinates of the shape long with the width and height. Just like the Ellipse it does not allow for rotation. |
| Polygon | Stores a shape with any number of vertices. |
Because we expect that the "circle" drawn by the user will not be a
perfect circle, we will use the
Polygon
shape to store the points. The impact of this is that the user could
really draw any shape they wanted, like perhaps a cloud shape, and
our
Polygon
will be able to store that.
For the purposes of a flag that allows the user to only draw one
circle, we will check to see if
targetArea
is
null
[2].
Next, in order to get access to the actual stroke made by the user we
need to get a handle to the
StrokeStorage
for the page, and then lookup the
Stroke
object based on when it was made
[3].
Now that we have the
Stroke
we can get the number of vertices in the
Stroke
and initialize our
targetArea
[4].
We then simply iterate over the vertices in the
Shape
and copy them over to the
targetArea
[5].
The reason for copying the stroke at all is because we will need to
call the
contains
method on the shape, and a
Stroke
object is not a closed object while a
Polygon
is. At the same time our code is making the assumption that the user
really did draw a circle and not just a line. We could add some
checking for that, verifying that the start and ending points are in
close proximity, but that is a bit overkill for this tutorial.
Now lets implement the
PenTipListener
interface and code the last part of the penlet where we check to see
if the pen is inside out outside of the circle.
Location, Location, Location
The
PenTipListener
interface has four methods that we need to implement. Take a look at
the code below, then we will discuss the one that matters to us, the
singleTap
method.
r
/* ***********************************************
*
* PenTipListener interface method.
*
*********************************************** */
public void singleTap (long time, int x, int y)
{
if (targetArea != null) {
if (targetArea.contains(x, y)) {
this.label.draw("inside", true);
}
else {
this.label.draw("outside", true);
}
}
}
public void doubleTap (long time, int x, int y)
{
}
public void penDown (long time, Region region, PageInstance pageInstance)
{
}
public void penUp (long time, Region region, PageInstance pageInstance)
{
}
Ok, the logic here is very simple. When the pen touches the paper the
singleTap
handler is called with the coordinates of the pen's tip. And in order
to test that our
targetArea
contains the point we call the
contains
method.
If the point is inside the circle we draw "inside" on the OLED display, and if it is outside the circle we display "outside".
Tada!
That concludes the sample application, but the API does offer some
additional tools for working with shapes. In particular you can use
the method
intersectsWith
on the shape to find its relationship to another shape.
intersectsWith
returns an
int
value that is one of
Shape.INTERSECT_CLIP
,
Shape.INTERSECT_EXTERNAL
,
Shape.INTERSECT_INTERNAL1
, or
Shape.INTERSECT_INTERNAL2
. The reason for two internal intersection constants is that the
first is returned when shape "A" is within shape "B", while the
second constant is the reverse.
You can also get the union of the shapes by calling
Shape.getUnion
. This returns a
Rectangle
that contains both shapes.
Of course if you are the math-enabled type, you could write your own functions to determine the geometric properties of drawn shapes.
You could even turn shape drawing into a game where the goal was to draw a perfect circle. The penlet could determine the center of the drawn circle and calculate a percentage of perfectness, displaying the result to the user. Hmmm... that could be interesting :)
Until next time, happy coding!
Page 1 » Page 2
Comments (View) blog comments powered by Disqus
Project Information
Tested for use with: PreRelease-SDK
Download the source code for this tutorial.
Download Source Code (zip)
New Tutorials
Using a Shared Library
Learn how to create a library of utils that you can
share between projects.
Capturing Drawn Shapes
Learn how to capture shapes drawn by the pen and determine relationships.
Penlets 101
Never written a penlet before? Then start here with Penlets 101!
Creating a Custom Vocabulary
Learn how to create a custom vocabulary for your ICR applications.
Using Properties Files
J2ME lacks a Properties class. In this tutorial we roll our own,
along with split and chomp functions.