90 * randRange(1, 3) ROTDEG * PI / 180 Geom.convexhull(_.map(randRange(-4, 4, 6, 2), function(p) { return { x: p[0], y: p[1] }; })) _.map(HULL, function(p) { return [p.x, p.y]; }) _.map(HULL, function(p) { return [p.x * cos(ROTRAD) - p.y * sin(ROTRAD), p.x * sin(ROTRAD) + p.y * cos(ROTRAD)]; })

What is the image of the polygon below after the rotation `T_{{ROTDEG}^\circ{} }`?

graphInit({ range: 11, scale: 20, axisArrows: "<->", tickStep: 1, labelStep: 1, gridOpacity: 0.05, axisOpacity: 0.2, tickOpacity: 0.4, labelOpacity: 0.5 }); addMouseLayer(); path(HULL_POINTS.concat(true), { stroke: GRAY, strokeDasharray: "- " }); graph.points = _.map(HULL_POINTS, function(point) { return addMovablePoint({ coord: point }); }); graph.lines = []; _(graph.points.length).times(function(i) { graph.lines.push(addMovableLineSegment({ pointA: graph.points[i], pointZ: graph.points[(i + 1) % graph.points.length], fixed: true })); }); graph.origOffsets = _.map(graph.points, function(point) { return atan2(point.coord[1], point.coord[0]) - roundToNearest(PI / 6, atan2(point.coord[1], point.coord[0])); }); _.each(graph.points, function(point) { point.onMove = function(x, y) { var myAng = atan2(this.coord[1], this.coord[0]); var newAng = atan2(y, x); graph.updatePolygon(newAng - myAng); return false; } point.onMoveEnd = function(x, y) { var possibleSnaps = [ graph.origOffsets[_.indexOf(graph.points, this)] + roundToNearest(PI/6, atan2(y,x)) - atan2(this.coord[1], this.coord[0]), graph.origOffsets[_.indexOf(graph.points, this)] + roundToNearest(PI/6, atan2(y,x)) + PI / 6 - atan2(this.coord[1], this.coord[0]), graph.origOffsets[_.indexOf(graph.points, this)] + roundToNearest(PI/6, atan2(y,x)) - PI / 6 - atan2(this.coord[1], this.coord[0]) ]; var absSnaps = _.map(possibleSnaps, function(rad) { return abs(rad); }); var absMoveTo = min(absSnaps[0], absSnaps[1], absSnaps[2]); var moveTo = _.find(possibleSnaps, function(rad) { return abs(rad) === absMoveTo; }); graph.updatePolygon(moveTo); } }); graph.updatePolygon = function(rad) { _.each(graph.points, function(point) { point.setCoord([ point.coord[0] * cos(rad) - point.coord[1] * sin(rad), point.coord[0] * sin(rad) + point.coord[1] * cos(rad) ]); point.updateLineEnds(); }); };
_.map(graph.points, function(point) { return point.coord; })
var closeEnough = function(points1, points2) { // put the two sets of points in the same order (if they're roughly the same) points1 = _.sortBy(points1, function(p) { return p[0] * 100 + p[1]; }); points2 = _.sortBy(points2, function(p) { return p[0] * 100 + p[1]; }); return _.all(points1, function(el, i) { return abs(points1[i][0] - points2[i][0]) < 0.01 && abs(points1[i][1] - points2[i][1]) < 0.01; }); }; if (closeEnough(guess, HULL_POINTS)) { return ""; } return closeEnough(guess, TARGET);
_.each(graph.points, function(point, n) { point.setCoord(guess[n]); point.updateLineEnds(); });

A rotation `T_{\LARGE{r^\circ{}}}` rotates points by `r` degrees around `(0,0)` counter-clockwise.

To see where a rotation moved this polygon, pick one point and rotate it. For example, what happens to `( HULL[0].x , HULL[0].y )` under this rotation?

circle([HULL[0].x, HULL[0].y], { r: 0.2, fill: "black", stroke: "none" });

Under the rotation `T_{ROTDEG {}^\circ{} }`, `( HULL[0].x , HULL[0].y )` is translated to `( round(TARGET[0][0]) , round(TARGET[0][1]))`. Where is the rest of the polygon rotated?

circle(TARGET[0], { r: 0.2, fill: "black", stroke: "none" }); arc([0,0], sqrt(pow(HULL[0].x, 2) + pow(HULL[0].y, 2)), atan2(HULL[0].y, HULL[0].x) * 180 / PI, atan2(TARGET[0][1], TARGET[0][0]) * 180 / PI, { stroke: "black", arrows: "->" });

To get from `(HULL[0].x, HULL[0].y)` to `(round(TARGET[0][0]), round(TARGET[0][1]))`, we rotated it `ROTDEG{}^\circ{}` counter-clockwise, or through one quarter of a circle. To get from `(HULL[0].x, HULL[0].y)` to `(round(TARGET[0][0]), round(TARGET[0][1]))`, we rotated it `ROTDEG{}^\circ{}` counter-clockwise, or through one half of a circle. To get from `(HULL[0].x, HULL[0].y)` to `(round(TARGET[0][0]), round(TARGET[0][1]))`, we rotated it `ROTDEG{}^\circ{}` counter-clockwise, or through three quarters of a circle.

The orange outline shows where the polygon ends up after the translation.

for (var i=0; i < TARGET.length; i++) { line(TARGET[i], TARGET[(i+1) % TARGET.length], { stroke: ORANGE }); }

What is the transformation that rotates the blue solid shape to the orange dashed shape?

graphInit({ range: 11, scale: 20, axisArrows: "<->", tickStep: 1, labelStep: 1, gridOpacity: 0.05, axisOpacity: 0.2, tickOpacity: 0.4, labelOpacity: 0.5 }); path(HULL_POINTS.concat(true), { stroke: BLUE }); path(TARGET.concat(true), { stroke: ORANGE, strokeDasharray: "- " });
`{\LARGE T}` function(guess, maxError) { var correct = false; var symmetries = _.map(Geom.rotationalSymmetries(HULL), function(rad) { return rad / PI * 180; }).concat(360); return _.any(symmetries, function(sym) { return abs((((guess - ROTDEG + sym) % 360) + 360 + 180) % 360 - 180) < maxError; }); } `{}^\circ{}`

A rotation `T_{\LARGE{r^\circ{}}}` rotates points by `r` degrees around `(0, 0)` counter-clockwise.

To see what rotation moved the blue polygon, pick one point and rotate it. For example, what happened to `(HULL[0].x, HULL[0].y)` under this rotation?

circle([HULL[0].x, HULL[0].y], { r: 0.2, fill: "black", stroke: "none" });

Under this rotation, `(HULL[0].x, HULL[0].y)` was rotated to `(round(TARGET[0][0]), round(TARGET[0][1]))`. What does this tell you about the rotation used?

circle(TARGET[0], { r: 0.2, fill: "black", stroke: "none" }); arc([0, 0], sqrt(pow(HULL[0].x, 2) + pow(HULL[0].y, 2)), atan2(HULL[0].y, HULL[0].x) * 180 / PI, atan2(TARGET[0][1], TARGET[0][0]) * 180 / PI, { stroke: "black", arrows: "->" });

To get from `(HULL[0].x, HULL[0].y)` to `(round(TARGET[0][0]), round(TARGET[0][1]))`, we rotated it around `(0, 0)` `ROTDEG{}^\circ{}` counterclockwise.

The rotation used was `T_{ROTDEG^\circ{}}`.