Java Reference
In-Depth Information
This comes from the definition of what the sine of an angle is. The
Math
class provides a method to
calculate
sin-1
values (also called arcsine values), so we can calculate
angle
as:
double angle = Math.asin(perp/hypotenuse);
The
asin()
method returns an angle in radians between -
/2, which is fine for us. We are
unlikely to create an angle outside this range for a
mouseDragged()
event.
π
/2 and
π
Of course, we need to know which way the rotation is going, clockwise or counterclockwise. Another
static method in the
Line2D
class can help out here. The
relativeCCW()
method determines where
a point lies with respect to a line. If you have to rotate the line clockwise to reach the point, the method
returns -1, and if you have to rotate the line counterclockwise it returns +1. We can use this to test
whether the point,
last
, is clockwise or counterclockwise with respect to the line from
position
to
start
. Since angles rotating the coordinate system clockwise are positive, we can calculate a suitably
signed value for
angle
with the statement:
double angle = -Line2D.relativeCCW(position.x, position.y,
start.x, start.y,
last.x, last.y)*Math.asin(perp/hypotenuse);
The minus sign is necessary because the method returns -1 when
last
is clockwise with respect to the
line from
position
to
start
. That's all the math we need. Let's do it.
Try It Out - Rotating Elements
To deal with
ROTATE
mode in the
mouseDragged()
method, we can add an extra
else
if
clause
after the one we added for
MOVE
:
} else if(button1Down && mode == ROTATE && selectedElement != null) {
selectedElement.draw(g2D); // Draw to erase the element
selectedElement.rotate(getAngle(selectedElement.getPosition(),
start, last));
selectedElement.draw(g2D); // Draw in its new position
start = last; // Make start current point
}
After drawing the element to erase it, we call its
rotate()
method to rotate it and then redraw it in the
new position. We will add the definition for the
rotate()
method to the
Element
class in a moment.
The argument to the
rotate()
method is the angle in radians through which the element is to be
rotated, and that is returned by a helper method,
getAngle()
. We can add that to the
MouseHandler
class as:
// Helper method for calculating getAngle()
double getAngle(Point position, Point start, Point last) {
// Get perpendicular distance from last to the line from position to start
double perp = Line2D.ptLineDist(position.x, position.y,
last.x, last.y, start.x, start.y);
// Get the distance from position to start
double hypotenuse = position.distance(start);