Path2D GeometricRecognizer::resample(Path2D points) { double interval = pathLength(points) / (numPointsInGesture - 1); // interval length double D = 0.0; Path2D newPoints; //--- Store first point since we'll never resample it out of existence newPoints.push_back(points.front()); for(int i = 1; i < (int)points.size(); i++) { Point2D currentPoint = points[i]; Point2D previousPoint = points[i-1]; double d = getDistance(previousPoint, currentPoint); if ((D + d) >= interval) { double qx = previousPoint.x + ((interval - D) / d) * (currentPoint.x - previousPoint.x); double qy = previousPoint.y + ((interval - D) / d) * (currentPoint.y - previousPoint.y); Point2D point(qx, qy); newPoints.push_back(point); points.insert(points.begin() + i, point); D = 0.0; } else D += d; } // somtimes we fall a rounding-error short of adding the last point, so add it if so if (newPoints.size() == (numPointsInGesture - 1)) { newPoints.push_back(points.back()); } return newPoints; }
/** * Shift the points so that the center is at 0,0. * That way, if everyone centers at the same place, we can measure * the distance between each pair of points without worrying about * where each point was originally drawn * If we didn't do this, shapes drawn at the top of the screen * would have a hard time matching shapes drawn at the bottom * of the screen */ Path2D GeometricRecognizer::translateToOrigin(Path2D points) { Point2D c = centroid(points); Path2D newPoints; for (Path2DIterator i = points.begin(); i != points.end(); i++) { Point2D point = *i; double qx = point.x - c.x; double qy = point.y - c.y; newPoints.push_back(Point2D(qx, qy)); } return newPoints; }
Path2D GeometricRecognizer::rotateBy(Path2D points, double rotation) { Point2D c = centroid(points); //--- can't name cos; creates compiler error since VC++ can't //--- tell the difference between the variable and function double cosine = cos(rotation); double sine = sin(rotation); Path2D newPoints; for (Path2DIterator i = points.begin(); i != points.end(); i++) { Point2D point = *i; double qx = (point.x - c.x) * cosine - (point.y - c.y) * sine + c.x; double qy = (point.x - c.x) * sine + (point.y - c.y) * cosine + c.y; newPoints.push_back(Point2D(qx, qy)); } return newPoints; }
Path2D GeometricRecognizer::scaleToSquare(Path2D points) { //--- Figure out the smallest box that can contain the path DollarRecognizer::Rectangle box = boundingBox(points); Path2D newPoints; for (Path2DIterator i = points.begin(); i != points.end(); i++) { Point2D point = *i; //--- Scale the points to fit the main box //--- So if we wanted everything 100x100 and this was 50x50, //--- we'd multiply every point by 2 double scaledX = point.x * (this->squareSize / box.width); double scaledY = point.y * (this->squareSize / box.height); //--- Why are we adding them to a new list rather than //--- just scaling them in-place? // TODO: try scaling in place (once you know this way works) newPoints.push_back(Point2D(scaledX, scaledY)); } return newPoints; }