/* Copyright 1996 Rujith de Silva.
Modified 2002-03-02
*/
package rujith.pentominoes;
import java.lang.Math;
/**
* An oriented position that can be moved and rotated by dragging. It
* maintains the following information: an (x,y) position, and an
* orientation (expressed as an angle). This can be grabbed by a
* handle at another point (hx, hy), and then that handle point can be
* moved around to new locations. The piece's position and
* orientation is moved according to how the handle is moved,
* imitating the movement of a solid body grabbed at a point near or
* far from its centre.
*/
public class Position extends Object
{
/**
* X-position of the object
*/
public double x = 0.0;
/**
* Y-position of the object
*/
public double y = 0.0;
/**
* Azimuth (orientation) of the object.
*/
public double azimuth = 0.0;
// The handle's position
private double hx, hy;
private double handleDistance;
private boolean handleSet = false;
/**
* The radius that leads to rotation. If the handle's distance
* from the object's position is longer than this radius, then the
* object will rotate and move as the handle is moved; otherwise
* the object will move without rotating.
*/
public double nonRotateRadius = 0.0;
/**
* Create a new position with zero azimuth
*
* @param x Object's initial X-position
* @param y Object's initial Y-position
*/
public Position (double x, double y)
{
this.x = x;
this.y = y;
}
/**
* Set the handle to a new position. Sets the azimuth to zero.
* This method should be called before calling move.
*
* @param x Handle's new x position
* @param y Handle's new y position
*
* @return True if the handle is far enough from the position that
* rotation would occur as the handle is moved
*/
synchronized public boolean reset (double x, double y)
{
this.hx = x;
this.hy = y;
this.handleSet = true;
this.azimuth = 0.0;
double diffx = this.hx - this.x;
double diffy = this.hy - this.y;
this.handleDistance =
Math.sqrt (diffx * diffx + diffy * diffy);
return this.handleDistance > this.nonRotateRadius;
}
/**
* Move the handle, and move and rotate the position accordingly.
* The handle's position must have been set before (so the typical
* pattern is to call reset, then call
* move zero or more times, and then repeat this
* cycle multiple times.
*
* @param newx Handle's new X-position
* @param newy Handle's new Y-position
*/
synchronized public void move (double newx, double newy)
{
// Handle must have been set already.
if (! this.handleSet) return;
// Get vector to the handle's original position
double olddiffx = this.hx - this.x;
double olddiffy = this.hy - this.y;
// Get vector to the handle's new position
double newdiffx = newx - this.x;
double newdiffy = newy - this.y;
// If the handle was far enough away ...
if (this.handleDistance > this.nonRotateRadius)
{
// Rotate the piece as well as move it. Turn the position
// by the angle between the handle's original bearing, and
// its new bearing.
double oldangle = Math.atan2 (olddiffy, olddiffx);
double newangle = Math.atan2 (newdiffy, newdiffx);
double anglediff = newangle - oldangle;
this.azimuth += anglediff;
this.azimuth %= 2.0 * Math.PI;
// And the position should be the same distance away from
// the handle's new position, along the new angle.
this.x = newx - this.handleDistance * Math.cos(newangle);
this.y = newy - this.handleDistance * Math.sin(newangle);
}
else
{
// Simply translate the position by the vector the handle
// moved.
this.x += newx - this.hx;
this.y += newy - this.hy;
}
// Update the handle to its new position, ready for another
// call to move(...).
this.hx = newx;
this.hy = newy;
}
}