/** * 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; }
Point2D GeometricRecognizer::centroid(Path2D points) { double x = 0.0, y = 0.0; for (Path2DIterator i = points.begin(); i != points.end(); i++) { Point2D point = *i; x += point.x; y += point.y; } x /= points.size(); y /= points.size(); return Point2D(x, y); }
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; }
Rectangle GeometricRecognizer::boundingBox(Path2D points) { double minX = MAX_DOUBLE; double maxX = -MAX_DOUBLE; double minY = MAX_DOUBLE; double maxY = -MAX_DOUBLE; for (Path2DIterator i = points.begin(); i != points.end(); i++) { Point2D point = *i; if (point.x < minX) minX = point.x; if (point.x > maxX) maxX = point.x; if (point.y < minY) minY = point.y; if (point.y > maxY) maxY = point.y; } Rectangle bounds(minX, minY, (maxX - minX), (maxY - minY)); return bounds; }