// // ProjectionControlJ3D.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.java3d; import visad.*; import java.rmi.*; import javax.media.j3d.*; import javax.vecmath.*; import java.util.Vector; import java.util.Enumeration; import java.lang.reflect.*; /** ProjectionControlJ3D is the VisAD class for controlling the Projection from 3-D to 2-D. It manipulates a TransformGroup node in the scene graph.<P> */ /* WLH 17 June 98 public class ProjectionControlJ3D extends Control implements ProjectionControl { */ public class ProjectionControlJ3D extends ProjectionControl { private transient Transform3D Matrix; // Vector of Switch nodes for volume rendering transient Vector switches = new Vector(); int which_child = 2; // initial view along Z axis (?) // DRM 6 Nov 2000 /** View of the postive X face of the display cube */ public static final int X_PLUS = 0; /** View of the negative X face of the display cube */ public static final int X_MINUS = 1; /** View of the postive Y face of the display cube */ public static final int Y_PLUS = 2; /** View of the negative Y face of the display cube */ public static final int Y_MINUS = 3; /** View of the postive Z face of the display cube */ public static final int Z_PLUS = 4; /** View of the negative Z face of the display cube */ public static final int Z_MINUS = 5; /** * Construct a new ProjectionControl for the display. The initial * projection is saved so it can be reset with resetProjection(). * @see #resetProjection(). * @param d display whose projection will be controlled by this * @throws VisADException */ public ProjectionControlJ3D(DisplayImpl d) throws VisADException { super(d); // WLH 8 April 99 // Matrix = new Transform3D(); Matrix = init(); matrix = new double[MATRIX3D_LENGTH]; Matrix.get(matrix); saveProjection(); // DRM 6 Nov 2000 /* WLH 8 April 99 Matrix = init(); matrix = new double[MATRIX3D_LENGTH]; Matrix.get(matrix); ((DisplayRendererJ3D) getDisplayRenderer()).setTransform3D(Matrix); */ } /** * Set the projection matrix. * @param m new projection matrix * @throws VisADException VisAD error * @throws RemoteException remote error */ public void setMatrix(double[] m) throws VisADException, RemoteException { super.setMatrix(m); Matrix = new Transform3D(matrix); VisADCanvasJ3D canvas = ((DisplayRendererJ3D) getDisplayRenderer()).getCanvas(); if (canvas != null && canvas.getOffscreen()) { try { Method renderMethod = Canvas3D.class.getMethod("renderOffScreenBuffer", new Class[] {}); renderMethod.invoke(canvas, new Object[] {}); Method waitMethod = Canvas3D.class.getMethod("waitForOffScreenRendering", new Class[] {}); waitMethod.invoke(canvas, new Object[] {}); } catch (NoSuchMethodException e) { // System.out.println(e); } catch (IllegalAccessException e) { // System.out.println(e); } catch (InvocationTargetException e) { // System.out.println(e + "\n" + // ((InvocationTargetException) e).getTargetException()); } // canvas.renderOffScreenBuffer(); } ((DisplayRendererJ3D) getDisplayRenderer()).setTransform3D(Matrix); if (!switches.isEmpty()) selectSwitches(); // WLH 5 May 2000 // changeControl(true); changeControl(false); } /** * Set the aspect for the axes. Default upon initialization is * 1.0, 1.0, 1.0. Invokes saveProjection to set this as the new default. * @see #saveProjection() * @param aspect ratios (dimension 3) for the X, Y, and Z axes * @throws VisADException aspect is null or wrong dimension or other error * @throws RemoteException remote error */ public void setAspect(double[] aspect) throws VisADException, RemoteException { if (aspect == null || aspect.length != 3) { throw new DisplayException("aspect array must be length = 3"); } Transform3D transform = new Transform3D(); transform.setScale(new javax.vecmath.Vector3d(aspect[0], aspect[1], aspect[2])); double[] mult = new double[MATRIX3D_LENGTH]; transform.get(mult); Transform3D mat = init(); double[] m = new double[MATRIX3D_LENGTH]; mat.get(m); setMatrix(getDisplay().multiply_matrix(mult, m)); saveProjection(); // DRM 6 Nov 2000 } private Transform3D init() { Transform3D mat = new Transform3D(); // initialize scale double scale = 0.5; if (getDisplayRenderer().getMode2D()) scale = ProjectionControl.SCALE2D; Transform3D t1 = new Transform3D( MouseBehaviorJ3D.static_make_matrix(0.0, 0.0, 0.0, scale, 0.0, 0.0, 0.0) ); mat.mul(t1); return mat; } public void addPair(Switch sw, DataRenderer re) { switches.addElement(new SwitchProjection(sw, re)); sw.setWhichChild(which_child); } private void selectSwitches() { int old_which_child = which_child; // calculate which axis is most parallel to eye direction Transform3D tt = new Transform3D(Matrix); tt.invert(); Point3d origin = new Point3d(0.0, 0.0, 0.0); Point3d eye = new Point3d(0.0, 0.0, 1.0); tt.transform(origin); tt.transform(eye); double dx = eye.x - origin.x; double dy = eye.y - origin.y; double dz = eye.z - origin.z; double ax = Math.abs(dx); double ay = Math.abs(dy); double az = Math.abs(dz); if (az >= ay && az >= ax) { which_child = (dz > 0) ? 2 : 5; } else if (ay >= ax) { which_child = (dy > 0) ? 1 : 4; } else { which_child = (dx > 0) ? 0 : 3; } // axis did not change, so no need to change Switches if (old_which_child == which_child) return; /* System.out.println("which_child = " + which_child + " " + dx + " " + dy + " " + dz); */ // axis changed, so change Switches Enumeration pairs = ((Vector) switches.clone()).elements(); while (pairs.hasMoreElements()) { SwitchProjection ss = (SwitchProjection) pairs.nextElement(); ss.swit.setWhichChild(which_child); } } /** clear all 'pairs' in switches that involve re */ public void clearSwitches(DataRenderer re) { Enumeration pairs = ((Vector) switches.clone()).elements(); while (pairs.hasMoreElements()) { SwitchProjection ss = (SwitchProjection) pairs.nextElement(); if (ss.renderer.equals(re)) { switches.removeElement(ss); } } } /** * Set the projection so the requested view is displayed. * @param view one of the static view fields (X_PLUS, X_MINUS, etc). This * will set the view so the selected face is orthogonal to * the display. * @throws VisADException VisAD failure. * @throws RemoteException Java RMI failure. */ public void setOrthoView(int view) throws VisADException, RemoteException { double[] viewMatrix; if (getDisplayRenderer().getMode2D()) return; switch (view) { case Z_PLUS: // Top viewMatrix = getDisplay().make_matrix(0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0); break; case Z_MINUS: // Bottom viewMatrix = getDisplay().make_matrix(0.0, 180.0, 0.0, 1.0, 0.0, 0.0, 0.0); break; case Y_PLUS: // North viewMatrix = getDisplay().make_matrix(-90.0, 180.0, 0.0, 1.0, 0.0, 0.0, 0.0); break; case Y_MINUS: // South viewMatrix = getDisplay().make_matrix(90.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0); break; case X_PLUS: // East viewMatrix = getDisplay().make_matrix(0.0, 90.0, 90.0, 1.0, 0.0, 0.0, 0.0); break; case X_MINUS: // West viewMatrix = getDisplay().make_matrix(0.0, -90.0, -90.0, 1.0, 0.0, 0.0, 0.0); break; default: // no change viewMatrix = getDisplay().make_matrix(0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0); break; } setMatrix( getDisplay().multiply_matrix(viewMatrix, getSavedProjectionMatrix())); } /** SwitchProjection is an inner class of ProjectionControlJ3D for (Switch, DataRenderer) structures */ private class SwitchProjection extends Object { Switch swit; DataRenderer renderer; SwitchProjection(Switch sw, DataRenderer re) { swit = sw; renderer = re; } } }