// Written by Nick Winter // Used in Chloe Fan's WiiPaint 2 and 3 // July 2008 package { import Math; // 0 for unrecognized shape, 4 for square, 3 for triangle, 1 for line function Recognize(points:Array):Array { if (square(points).length > 0) return [4, square(points)]; if (triangle(points).length > 0) return [3, triangle(points)]; if (line(points).length > 0) return [1, line(points)]; return [0, []]; } } // line() checks to see if each line segment with length intervalLength has an angle no more different // than pi/8 from the last, or if an angle is given, no more different from the given angle than pi/8. function line(points:Array, theta:Number=-3025):Array { if (points.length < 10) { return []; }// don't even try if there are less than 10 points recorded var intervalPoints:Array = []; var intervalLength:Number = 30; var x:Number = points[0][0]; var y:Number = points[0][1]; var angle:Number = Math.atan2(-1*(points[4][1] - y), points[4][0] - x); var distx:Number = points[0][0]; var disty:Number = points[0][1]; var dist:Number = 0; var startIndex:int = 0; for each (var p:Array in points) { dist += Math.sqrt(Math.pow(distx-p[0], 2) + Math.pow(disty-p[1], 2)); if (dist > intervalLength * 2) {// ignore the first bit, it's usually jerky break; } startIndex += 1; distx = p[0]; disty = p[1]; } intervalPoints.push([distx, disty]); dist = 0; x = distx; y = disty; for (var i:int = startIndex+1; i < points.length - startIndex; i++) { // skip the beginning and end var newx:Number = points[i][0]; var newy:Number = points[i][1]; dist = Math.sqrt(Math.pow(newx - x, 2) + Math.pow(newy - y, 2)); if (dist < intervalLength) { //trace(dist); continue; // only compare points every "intervalLength" pixels } intervalPoints.push([newx, newy]); var newangle:Number = Math.atan2(-1*(newy - y), newx - x); if (theta != -3025) { if (Math.abs(newangle - theta) > 2*Math.PI/8) { //trace((newx - x) + "\t" + (newy - y) + "\t" + theta + "\t" + newangle + "\t" + (newangle - theta)); return []; } } var diff:Number = Math.abs(newangle - angle); if (diff > Math.PI/8) {// make sure the angle hasn't changed too much in the past intervalLength pixels //trace((newx - x) + "\t" + (newy - y) + "\t" + angle + "\t" + newangle + "\t" + diff); return []; } x = newx; y = newy; angle = newangle; } return intervalPoints; } function square(points:Array):Array { var segments = segmentate(points, Math.PI/2)[0]; var turningPoints = segmentate(points, Math.PI/2)[1]; if (segments.length != 4) return []; if (line(segments[0], 0) != [] && line(segments[1], 3*Math.PI/2) != []&& line(segments[2], Math.PI) != [] && line(segments[3], Math.PI/2) != []) { return [segments, turningPoints]; } return []; } function triangle(points:Array):Array { var segments = segmentate(points, 2*Math.PI/3)[0]; var turningPoints = segmentate(points, 2*Math.PI/3)[1]; if (segments.length != 3) return []; if (line(segments[0]) != [] && line(segments[1]) != []&& line(segments[2]) != []) { return [segments, turningPoints]; } return []; } function segmentate(points:Array, theta:Number):Array { if (points.length < 15) { return []; }// don't even try if there are less than 15 points recorded var turningPoints:Array = []; var segments:Array = [[]]; var intervalLength:Number = 50; var x:Number = points[0][0]; var y:Number = points[0][1]; var angle:Number = Math.atan2(-1*(points[4][1] - y), points[4][0] - x); var distx:Number = points[0][0]; var disty:Number = points[0][1]; var dist:Number = 0; var startIndex:int = 0; for each (var p:Array in points) { dist += Math.sqrt(Math.pow(distx-p[0], 2) + Math.pow(disty-p[1], 2)); if (dist > intervalLength * 2) {// ignore the first bit, it's usually jerky break; } startIndex += 1; distx = p[0]; disty = p[1]; segments[0].push(p); } dist = 0; x = distx; y = disty; var lastdiff:Number = 0; for (var i:int = startIndex+1; i < points.length - startIndex; i++) { // skip the beginning and end segments[segments.length-1].push(points[i]) var newx:Number = points[i][0]; var newy:Number = points[i][1]; dist = Math.sqrt(Math.pow(newx - x, 2) + Math.pow(newy - y, 2)); if (dist < intervalLength) { continue; // only compare points every "intervalLength" pixels } var newangle:Number = Math.atan2(-1*(newy - y), newx - x); //if (newangle < 0) newangle += 2*Math.PI; // convert all angles to positive? var diff:Number = Math.abs(newangle - angle); if (angle > Math.PI/2 && newangle < -1*Math.PI/2) { diff = 2*Math.PI + newangle - angle; } else if (angle < -1*Math.PI/2 && newangle > Math.PI/2) { diff = 2*Math.PI - newangle + angle; } //trace("ANG\t" + angle + "\t" + newangle + "\t" + diff); if (diff + lastdiff > 0.75*theta) {// segmentate if we've covered more than 75% of the required angle in the last interval //trace("SEG\t" + x + "\t" + y + "\t" + angle + "\t" + newangle + "\t" + diff); segments.push([]); turningPoints.push([x, y]); diff = 0; } x = newx; y = newy; angle = newangle; lastdiff = diff; } return [segments, turningPoints]; }