package pixelapp.roation; import java.awt.*; /** * Created by IntelliJ IDEA. * User: pepijn * Date: Aug 7, 2005 * Time: 5:18:33 PM * To change this template use File | Settings | File Templates. */ class ArcBall { private static final float Epsilon = 1.0e-5f; Vector3f StVec; //Saved click vector Vector3f EnVec; //Saved drag vector float adjustWidth; //Mouse bounds width float adjustHeight; //Mouse bounds height public ArcBall(float NewWidth, float NewHeight) { StVec = new Vector3f(); EnVec = new Vector3f(); setBounds(NewWidth, NewHeight); } public void mapToSphere(Point point, Vector3f vector) { // Copy paramter into temp point Point2f tempPoint = new Point2f(point.x, point.y); // Adjust point coords and scale down to range of [-1 ... 1] tempPoint.x = (tempPoint.x * this.adjustWidth) - 1.0f; tempPoint.y = 1.0f - (tempPoint.y * this.adjustHeight); // Compute the square of the length of the vector to the point from the center float length = (tempPoint.x * tempPoint.x) + (tempPoint.y * tempPoint.y); // If the point is mapped outside of the sphere... (length > radius squared) if (length > 1.0f) { // Compute a normalizing factor (radius / sqrt(length)) float norm = (float) (1.0 / Math.sqrt(length)); // Return the "normalized" vector, a point on the sphere vector.x = tempPoint.x * norm; vector.y = tempPoint.y * norm; vector.z = 0.0f; } else //Else it's on the inside { // Return a vector to a point mapped inside the sphere // sqrt(radius squared - length) vector.x = tempPoint.x; vector.y = tempPoint.y; vector.z = (float) Math.sqrt(1.0f - length); } } public void setBounds(float NewWidth, float NewHeight) { assert((NewWidth > 1.0f) && (NewHeight > 1.0f)); // Set adjustment factor for width/height adjustWidth = 1.0f / ((NewWidth - 1.0f) * 0.5f); adjustHeight = 1.0f / ((NewHeight - 1.0f) * 0.5f); } // Mouse down public void click(Point NewPt) { mapToSphere(NewPt, this.StVec); } // Mouse drag, calculate rotation public void drag(Point NewPt, Quat4f NewRot) { // Map the point to the sphere this.mapToSphere(NewPt, EnVec); // Return the quaternion equivalent to the rotation if (NewRot != null) { Vector3f Perp = new Vector3f(); // Compute the vector perpendicular to the begin and end vectors Vector3f.cross(Perp, StVec, EnVec); // Compute the length of the perpendicular vector if (Perp.length() > Epsilon) //if its non-zero { // We're ok, so return the perpendicular vector as the transform // after all NewRot.x = Perp.x; NewRot.y = Perp.y; NewRot.z = Perp.z; // In the quaternion values, w is cosine (theta / 2), // where theta is rotation angle NewRot.w = Vector3f.dot(StVec, EnVec); } else //if its zero { // The begin and end vectors coincide, so return an identity transform NewRot.x = NewRot.y = NewRot.z = NewRot.w = 0.0f; } } } }