// // MouseBehaviorJ2D.java // /* VisAD system for interactive analysis and visualization of numerical data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and Tommy Jasmin. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ package visad.java2d; import visad.*; import java.lang.reflect.*; import java.awt.geom.AffineTransform; import java.awt.geom.NoninvertibleTransformException; /** MouseBehaviorJ2D is the VisAD class for mouse behaviors for Java2D */ public class MouseBehaviorJ2D implements MouseBehavior { /** DisplayRenderer for Display */ DisplayRendererJ2D display_renderer; DisplayImpl display; private MouseHelper helper = null; /** * Construct a MouseBehavior for the DisplayRenderer specified * @param r DisplayRenderer to use */ public MouseBehaviorJ2D(DisplayRendererJ2D r) { this(r, MouseHelper.class); } /** * Construct a MouseBehavior for the DisplayRenderer specified * @param r DisplayRenderer to use * @param mhClass MouseHelper subclass to use */ public MouseBehaviorJ2D(DisplayRendererJ2D r, Class mhClass) { try { Class[] param = new Class[] {DisplayRenderer.class, MouseBehavior.class}; Constructor mhConstructor = mhClass.getConstructor(param); helper = (MouseHelper) mhConstructor.newInstance(new Object[] {r, this}); } catch (Exception e) { throw new VisADError("cannot construct " + mhClass); } // helper = new MouseHelper(r, this); display_renderer = r; display = display_renderer.getDisplay(); } /** * Get the helper class used by this MouseBehavior. * The <CODE>MouseHelper</CODE> defines the actions taken based * on <CODE>MouseEvent</CODE>s. * @return <CODE>MouseHelper</CODE> being used. */ public MouseHelper getMouseHelper() { return helper; } /** * Return the VisAD ray corresponding to the component coordinates. * @param screen_x x coordinate of the component * @param screen_y y coordinate of the component * @return corresponding VisADRay * @see visad.VisADRay * @see visad.LocalDisplay#getComponent() */ public VisADRay findRay(int screen_x, int screen_y) { // System.out.println("findRay " + screen_x + " " + screen_y); VisADCanvasJ2D canvas = display_renderer.getCanvas(); AffineTransform trans = canvas.getTransform(); if (trans == null) return null; double[] coords = {(float) screen_x, (float) screen_y}; double[] newcoords = new double[2]; try { trans.inverseTransform(coords, 0, newcoords, 0, 1); } catch (NoninvertibleTransformException e) { throw new VisADError("MouseBehaviorJ2D.findRay: " + "non-invertable transform"); } VisADRay ray = new VisADRay(); ray.position[0] = newcoords[0]; ray.position[1] = newcoords[1]; ray.position[2] = 0.0; ray.vector[0] = 0.0; ray.vector[1] = 0.0; ray.vector[2] = -1.0; return ray; } /** * Return the VisAD ray corresponding to the VisAD cursor coordinates. * @param cursor array (x,y) of cursor location * @return corresponding VisADRay * @see visad.VisADRay * @see visad.DisplayRenderer#getCursor() */ public VisADRay cursorRay(double[] cursor) { VisADRay ray = new VisADRay(); ray.position[0] = cursor[0]; ray.position[1] = cursor[1]; ray.position[2] = 0.0; ray.vector[0] = 0.0; ray.vector[1] = 0.0; ray.vector[2] = -1.0; return ray; } /** * Return the screen coordinates corresponding to the VisAD coordinates. * @param position array of VisAD coordinates * @return corresponding (x, y) screen coordinates */ public int[] getScreenCoords(double[] position) { VisADCanvasJ2D canvas = display_renderer.getCanvas(); AffineTransform trans = canvas.getTransform(); if (trans == null) return null; double[] newcoords = new double[2]; trans.transform(position, 0, newcoords, 0, 1); int[] coords = new int[2]; for (int i=0; i<2; i++) coords[i] = (int) newcoords[i]; return coords; } /** * Create a translation matrix. * @param transx x translation amount * @param transy y translation amount * @param transz z translation amount * @return new translation matrix. This can be used to translate * the current matrix * @see #multiply_matrix(double[] a, double[] b) */ public double[] make_translate(double transx, double transy, double transz) { return make_matrix(0.0, 0.0, 0.0, 1.0, transx, -transy, transz); } /** * Create a translation matrix. * @param transx x translation amount * @param transy y translation amount * @return new translation matrix. This can be used to translate * the current matrix * @see #multiply_matrix(double[] a, double[] b) */ public double[] make_translate(double transx, double transy) { return make_translate(transx, transy, 0.0); } /** * Multiply the two matrices together. * @param a first matrix * @param b second matrix * @return new resulting matrix */ public double[] multiply_matrix(double[] a, double[] b) { AffineTransform ta = new AffineTransform(a); AffineTransform tb = new AffineTransform(b); ta.concatenate(tb); double[] c = new double[6]; ta.getMatrix(c); return c; } /** * Make a transformation matrix to perform the given rotation, scale and * translation. This function uses the fast matrix post-concatenation * techniques from Graphics Gems. * @param rotx x rotation * @param roty y rotation * @param rotz z rotation * @param scale scaling factor * @param transx x translation * @param transy y translation * @param transz z translation * @return new matrix */ public double[] make_matrix(double rotx, double roty, double rotz, double scale, double transx, double transy, double transz) { return make_matrix(rotx, roty, rotz, scale, scale, scale, transx, transy, transz); } /** * Make a transformation matrix to perform the given rotation, scale and * translation. This function uses the fast matrix post-concatenation * techniques from Graphics Gems. * @param rotx x rotation * @param roty y rotation * @param rotz z rotation * @param scalex x scaling factor * @param scaley y scaling factor * @param scalez z scaling factor * @param transx x translation * @param transy y translation * @param transz z translation * @return new matrix */ public double[] make_matrix(double rotx, double roty, double rotz, double scalex, double scaley, double scalez, double transx, double transy, double transz) { double sx, sy, sz, cx, cy, cz, t; int i, j, k; double deg2rad = 1.0 / 57.2957; double[] matrix = new double[6]; double[][] mat = new double[4][4]; /* Get sin and cosine values */ sx = Math.sin(rotx * deg2rad); cx = Math.cos(rotx * deg2rad); sy = Math.sin(roty * deg2rad); cy = Math.cos(roty * deg2rad); sz = Math.sin(rotz * deg2rad); cz = Math.cos(rotz * deg2rad); /* Start with identity matrix */ mat[0][0] = 1.0; mat[0][1] = 0.0; mat[0][2] = 0.0; mat[0][3] = 0.0; mat[1][0] = 0.0; mat[1][1] = 1.0; mat[1][2] = 0.0; mat[1][3] = 0.0; mat[2][0] = 0.0; mat[2][1] = 0.0; mat[2][2] = 1.0; mat[2][3] = 0.0; mat[3][0] = 0.0; mat[3][1] = 0.0; mat[3][2] = 0.0; mat[3][3] = 1.0; /* Z Rotation */ for (i=0;i<4;i++) { t = mat[i][0]; mat[i][0] = t*cz - mat[i][1]*sz; mat[i][1] = t*sz + mat[i][1]*cz; } /* X rotation */ for (i=0;i<4;i++) { t = mat[i][1]; mat[i][1] = t*cx - mat[i][2]*sx; mat[i][2] = t*sx + mat[i][2]*cx; } /* Y Rotation */ for (i=0;i<4;i++) { t = mat[i][0]; mat[i][0] = mat[i][2]*sy + t*cy; mat[i][2] = mat[i][2]*cy - t*sy; } /* Scale */ for (i=0;i<3;i++) { mat[i][0] *= scalex; mat[i][1] *= scaley; mat[i][2] *= scalez; } /* Translation */ mat[0][3] = transx; mat[1][3] = transy; mat[2][3] = transz; matrix[0] = mat[0][0]; matrix[1] = mat[1][0]; matrix[2] = mat[0][1]; matrix[3] = mat[1][1]; matrix[4] = mat[0][3]; matrix[5] = mat[1][3]; return matrix; } static final double EPS = 0.000001; /** * Get the rotation, scale and translation parameters for the specified * matrix. Results are not valid for non-uniform aspect (scale). * @param rot array to hold x,y,z rotation values * @param scale array to hold scale value * @param trans array to hold x,y,z translation values */ public void instance_unmake_matrix(double[] rot, double[] scale, double[] trans, double[] matrix) { double sx, sy, sz, cx, cy, cz; int i, j; double[][] mat = new double[4][4]; double[][] nat = new double[4][4]; double scalex, scaley, scalez, cxa, cxb, cxinv; double[] scaleinv = new double[3]; if (rot == null || rot.length != 3) return; if (scale == null || !(scale.length != 1 || scale.length !=3)) return; if (trans == null || trans.length != 3) return; if (matrix == null || matrix.length != 6) return; /* Start with identity matrix */ mat[0][0] = 1.0; mat[0][1] = 0.0; mat[0][2] = 0.0; mat[0][3] = 0.0; mat[1][0] = 0.0; mat[1][1] = 1.0; mat[1][2] = 0.0; mat[1][3] = 0.0; mat[2][0] = 0.0; mat[2][1] = 0.0; mat[2][2] = 1.0; mat[2][3] = 0.0; mat[3][0] = 0.0; mat[3][1] = 0.0; mat[3][2] = 0.0; mat[3][3] = 1.0; mat[0][0] = matrix[0]; mat[1][0] = matrix[1]; mat[0][1] = matrix[2]; mat[1][1] = matrix[3]; mat[0][3] = matrix[4]; mat[1][3] = matrix[5]; /* translation */ /* WLH 24 March 2000, for consistency with change of 22 Dec 97 in static_make_matrix trans[0] = mat[3][0]; trans[1] = mat[3][1]; trans[2] = mat[3][2]; */ trans[0] = mat[0][3]; trans[1] = mat[1][3]; trans[2] = mat[2][3]; /* scale */ scalex = scaley = scalez = 0.0; for (i=0; i<3; i++) { scalex += mat[0][i] * mat[0][i]; scaley += mat[1][i] * mat[1][i]; scalez += mat[2][i] * mat[2][i]; } if (Math.abs(scalex - scaley) > EPS || Math.abs(scalex - scalez) > EPS) { // System.out.println("problem " + scalex + " " + scaley + " " + scalez); } if (scale.length == 1) { scale[0] = Math.sqrt((scalex + scaley + scalez)/3.0); scaleinv[0] = Math.abs(scale[0]) > EPS ? 1.0 / scale[0] : 1.0 / EPS; scaleinv[1] = scaleinv[2] = scaleinv[0]; } else { scale[0] = Math.sqrt(scalex); scale[1] = Math.sqrt(scaley); scale[2] = Math.sqrt(scalez); for (i=0; i<3; i++) { scaleinv[i] = Math.abs(scale[i]) > EPS ? 1.0 / scale[i] : 1.0 / EPS; } } for (i=0; i<3; i++) { for (j=0; j<3; j++) { nat[j][i] = scaleinv[j] * mat[j][i]; } } /* rotation */ sx = -nat[2][1]; cxa = Math.sqrt(nat[2][0]*nat[2][0] + nat[2][2]*nat[2][2]); cxb = Math.sqrt(nat[0][1]*nat[0][1] + nat[1][1]*nat[1][1]); if (Math.abs(cxa - cxb) > EPS) { // System.out.println("problem2 " + cxa + " " + cxb); } /* the sign of cx does not matter; it is an ambiguity in 3-D rotations: (rotz, rotx, roty) = (180+rotz, 180-rotx, 180+roty) */ cx = (cxa + cxb) / 2.0; if (Math.abs(cx) > EPS) { cxinv = 1.0 / cx; sy = nat[2][0] * cxinv; cy = nat[2][2] * cxinv; sz = nat[0][1] * cxinv; cz = nat[1][1] * cxinv; } else { /* if cx == 0 then roty and rotz are ambiguous: assume rotx = 0.0 */ sy = 0.0; cy = 1.0; sz = nat[0][2]; cz = nat[1][2]; } rot[0] = 57.2957 * Math.atan2(sx, cx); rot[1] = 57.2957 * Math.atan2(sy, cy); rot[2] = 57.2957 * Math.atan2(sz, cz); return; } }