Groups | Blog | Home
all groups > flash actionscript > april 2007 >

flash actionscript : Gesture/Pattern Recognition


Rothrock
4/1/2007 9:15:58 PM
I'm going through this excellent article about gesture recognition:
http://www.gamedev.net/reference/articles/article2039.asp#

It is working fairly well so far, but I'm only up to the part where it
simplifies the drawn gesture.

Basically you create an array of the points you draw (in my case with a mouse
drag).

Then to simplify the gesture you want to make some smaller number of evenly
spaced points along that shape. So that you come out with, say 32 or some such
number of points.

The algorithm presented basically starts adding up the distances between each
point and when it gets to a distance greater than or equal to 1/32 of the total
length it copies that point into the new spaced array.

This would work great if my original array had points that were spaced fairly
consistently. But both with onMouseMove and onEnterFrame I get far to disparate
spacing of my points. If I draw very slowly and carefully I get nice even
spacing, but even a moderate mouse drag is not even.

Anybody with me so far?

I do know a brute force kind of solution and that would be to do some kind of
average length for all the segments and then go through and split any overtly
long lengths into to segments. It is just some trig and a splice.

I'm just wondering if anybody has any other recommendations?

You can see what it looks like with the attached code. Past it into a Frame
action on frame 1. And have a small dot of one color set to export as dot and a
small dot of another color set to export as oDot.


function Point(x:Number, y:Number) {
this.x = x;
this.y = y;
return this;
}
//
// Set Up the drawing area
//
var drawPad:MovieClip = this.createEmptyMovieClip("drawPad", 100);
drawPad.createEmptyMovieClip("bg", 100);
with (drawPad.bg) {
beginFill(0x00ff00, 25);
moveTo(0, 0);
lineTo(550, 0);
lineTo(550, 600);
lineTo(0, 600);
lineTo(0, 0);
endFill();
}
var drawArea:MovieClip = this.createEmptyMovieClip("drawArea", 101);
with (drawArea) {
beginFill(0x00ff00, 50);
moveTo(0, 0);
lineTo(550, 0);
lineTo(550, 600);
lineTo(0, 600);
lineTo(0, 0);
endFill();
}
drawPad.setMask(drawArea);
drawPad.onPress = function() {
this.clear();
thePoints = new Array();
p0 = new Point(_xmouse, _ymouse);
this.moveTo(p0.x, p0.y);
thePoints.push(p0);
this.lineStyle(2, 0xff0000, 100);
this.onMouseMove = function() {
var p = new Point(_xmouse, _ymouse);
thePoints.push(p);
this.lineTo(p.x, p.y);
};
};
drawPad.onRelease = drawPad.onReleaseOutside=function () {
delete this.onMouseMove;
// work on a copy of the array
normalizeGesture(thePoints);
myArray = spacePoints(thePoints);
testSpacing();
};
function normalizeGesture(points:Array):Array {
//work on a copy of the array
var xMin:Number = points[0].x;
var yMin:Number = points[0].y;
var xMax:Number = points[0].x;
var yMax:Number = points[0].y;
for (var i = 1; i<points.length; i++) {
var pt = points[i];
if (xMin>pt.x) {
xMin = pt.x;
}
if (yMin>pt.y) {
yMin = pt.y;
}
if (xMax<pt.x) {
xMax = pt.x;
}
if (yMax<pt.y) {
yMax = pt.y;
}
}
var gWidth:Number = xMax-xMin;
var gHeight:Number = yMax-yMin;
// empty or single point stroke! no gesture here
if (gWidth == 0 && gHeight == 0) {
return null;
}
var sFactor:Number = (gWidth>=gHeight) ? 1/gWidth : 1/gHeight;
//
// TEMP TESTING THING
//
SCALE = sFactor;
for (var i = 0; i<points.length; i++) {
var pt = points[i];
pt.x *= sFactor;
pt.y *= sFactor;
}
}
function spacePoints(points:Array):Array {
var pointsPerStroke:Number = 12;
var spacedPoints:Array = new Array();
//get length of original stroke
var gestureLength:Number = 0;
for (var i = 1; i<points.length; i++) {
var dx:Number = points[i].x-points[i-1].x;
var dy:Number = points[i].y-points[i-1].y;
gestureLength += Math.sqrt(dx*dx+dy*dy);
}
var newSegLen:Number = gestureLength/(pointsPerStroke-1);
//
//The first point goes back in
//
spacedPoints.push(points[0]);
//
//traverse along points in the original gesture
//calculate distance as you go. When the distance is far enough
//add a point to the new space gesture array.
var endOldDist:Number = 0;
var startOldDist:Number = 0;
var newDist:Number = 0;
var curSegLen:Number = 0;
for (var i = 1; i<points.length; i++) {
var excess:Number = endOldDist-newDist;
if (excess>=newSegLen) {
newDist += newSegLen;
var ratio:Number = (newDist-startOldDist)/curSegLen;
var tmpX:Number = (points[i].x-points[i-1].x)*ratio+points[i-1].x;
var tmpY:Number = (points[i].y-points[i-1].y)*ratio+points[i-1].y;
spacedPoints.push(new Point(tmpX, tmpY));
} else {
var dx:Number = points[i].x-points[i-1].x;
var dy:Number = points[i].y-points[i-1].y;
curSegLen = Math.sqrt(dx*dx+dy*dy);
startOldDist = endOldDist;
endOldDist += curSegLen;
}
}
trace("original: "+thePoints.length+", spaced: "+spacedPoints.length);
return spacedPoints;
}
//
//
function testSpacing() {
for (var i = 0; i<myArray.length; i++) {
drawPad.attachMovie("dot", "dot"+i, 5000+i, {_x:myArray[i].x/SCALE,
_y:myArray[i].y/SCALE});
}
for (var i = 0; i<thePoints.length; i++) {
drawPad.attachMovie("oDot", "oDot"+i, 1000+i, {_x:thePoints[i].x/SCALE,
_y:thePoints[i].y/SCALE});
}
}
kglad
4/2/2007 2:28:36 AM
i'd create a 10x10 sensor movieclip. i'd position 10 rows and 10 columns of
these sensors adjacent to one another in an 100x100 shapeDetector movieclip.

i'd then transform the gesture to a 100x100 shape and use the 100 hitTests()
with the shapeDetector.sensor movieclips to determine the gesture.
abeall
4/2/2007 2:50:51 AM
You might also try contacting Grant Skinner:
Rothrock
4/2/2007 4:11:29 AM
Thanks. It turns out that my ability to translate whatever language that
tutorial was written for into Actionscript is not so good! :)

I've actually work that part out ? I was incrementing the measurement loop
incorrectly so I was going onto the next segment before I should have.

kglad ? I'm thinking this approach should give better results, but I'm not
sure. The dot product approach presented here takes things like direction into
acount and that could be important for whatever it is I want to do. I don't
think the hitTest method takes that into account. At this point I'm just trying
to experiment and learn.

abeall ? I've seen some of Grant Skinner's stuff and I'm just amazed. It
always makes me feel like Kathy Griffin: D-list Coder. That one is truly
amazing. Someday?
abeall
4/2/2007 2:27:36 PM
[quoted text, click to view]

AddThis Social Bookmark Button