/** * Attempts to return a rotation matrix corresponding to moving the plane between two cursor * positions, with a given initial rotation matrix in effect. * * @param rot0 initial rotation matrix * @param pos0 initial projected position * @param pos1 destination projected position * @return destination rotation matrix, or null * @see Projection#projRotate */ private double[] genericRotate(double[] rot0, Point2D.Double pos0, Point2D.Double pos1) { double[] rv0 = new double[3]; if (unproject(pos0, rv0) && getSkyviewProjecter().validPosition(new double[] {pos1.x, pos1.y})) { double[] unrot0 = Matrices.invert(rot0); double[] ru0 = Matrices.mvMult(unrot0, rv0); return getRotation(ru0, pos1, rot0); } else { return null; } }
@Override public double[] cursorRotate(double[] rot0, Point2D.Double pos0, Point2D.Double pos1) { /* Attempt the rotation that transforms a point from one * projected plane position to another. */ double[] rot1 = genericRotate(rot0, pos0, pos1); if (rot1 != null) { return rot1; } /* That may fail because one or other of the supplied points is * not in the projection region. In that case do something * that feels like dragging the sphere around. * This rotation could be improved. It is algebraically messy, * and it also does not transition smoothly from the genericRotate * case, though perhaps that's not possible in general. */ else { boolean reflect = isReflected(rot0); double fr = reflect ? -1 : +1; double phi = (pos1.x - pos0.x); double psi = (pos1.y - pos0.y); double[] rm = rot0; double[] sightvec = Matrices.mvMult(Matrices.invert(rm), new double[] {1, 0, 0}); double[] hvec = Matrices.normalise(Matrices.cross(sightvec, RZ)); rm = rotateAround(rm, hvec, -psi); rm = rotateAround(rm, RZ, -phi * fr); if (Matrices.mvMult(rm, RZ)[2] >= 0) { return rm; } else { double delta = Math.atan2(-rm[2], rm[8]); double alpha = Math.atan2(-rm[3], rm[4] * fr); delta = Math.min(+0.5 * Math.PI, delta); delta = Math.max(-0.5 * Math.PI, delta); return verticalRotate(delta, alpha, reflect); } } }