Re: detecting which dataRef the mouse is over

Hi Don and VisAD Listeners,

Don Murray wrote:
> 
> Paul-
> 
> Unfortunately, as Bill says, VisAD is hardwired so that mouse
> manipulation is
> done only with the right mouse button and the PickManipulationRenderer
> only works in 3D displays.   

You'll find attached (see below) a PickManipulationRendererJ2D.java
which works for 2D displays (without Java 3D). This file has been
altered from PickManipulation 3D by "Heftrich, Torsten, AVENTIS/DE"
<Heftrich@xxxxxxxxxxxxxxx>, who made the file available.

>However, you can listen to mouse events
(...)
> It would be nice if the MouseHelper could be configurable so direct
> manipulation could be done with any mouse button, but that's not
> the case.
> 

I personally would'd find it better if the left mouse button where for
picking, i.e. clicking on data, and the right mouse button were for
rotating display. This is because the user tries intuitively to pick
data with the left button. Rotating the dislay is less obvious and makes
less sense in 2D. However, this is all subjective stuff and I'm by no
means suggesting that one should change the standard behaviour.

However, it'd be better if the programmer could change the behaviour
without having to touch the VisAD source or having to extend sme class.
That is, I'd like to be able to use picking with the left button, and
rotating with the right. Also, this might simplify programming apps
where the left mouse button is "overloaded": it might pick data, it
might move the display, it might display the coordinates, if, say, some
checkbox is selected. Think of all those Mac users out there with a
single-button-mouse ;-) (I know, I know, in the Mac there are
metakeys...and I wish I had one too ;-)

Cheers,

Ugo

PS. The Pick Renderer:

// from  "Heftrich, Torsten, AVENTIS/DE" <Heftrich@xxxxxxxxxxxxxxx>
//
// PickManipulationRendererJ2D.java
//

/*
VisAD system for interactive analysis and visualization of numerical
data.  Copyright (C) 1996 - 2000 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
*/


import visad.*;
import visad.java2d.*;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Vector;
import java.util.Enumeration;
import java.rmi.*;

//import javax.media.j3d.*;

/**
   PickManipulationRendererJ3D is the VisAD class for direct
   manipulation of rubber band boxes
*/
public class PickManipulationRendererJ2D extends
DirectManipulationRendererJ2D {

  private int mouseModifiersMask = 0;
  private int mouseModifiersValue = 0;

  public PickManipulationRendererJ2D () {
    this (0, 0);
  }

  /** mmm and mmv determine whehter SHIFT or CTRL keys are required -
      this is needed since this is a greedy DirectManipulationRenderer
      that will grab any right mouse click (that intersects its 2-D
      sub-manifold) */
  public PickManipulationRendererJ2D (int mmm, int mmv) {
    super();
    mouseModifiersMask = mmm;
    mouseModifiersValue = mmv;
  }

  /** for use in drag_direct */
  private transient DataDisplayLink link = null;
  private transient DataReference ref = null;

  private float[][] spatialValues = null;
  /** index into spatialValues found by checkClose */
  private int closeIndex = -1;

  private int directManifoldDimension = -1;

  /** information calculated by checkDirect */
  /** explanation for invalid use of DirectManipulationRenderer */
  private String whyNotDirect = null;

  /** possible values for whyNotDirect */
  private final static String notSimpleField
    "not simple field";
  private final static String notSimpleTuple
    "not simple tuple";

  private boolean stop = false;

  public void checkDirect() throws VisADException, RemoteException {
    setIsDirectManipulation(false);

    DisplayImpl display = getDisplay();

    DataDisplayLink[] Links = getLinks();
    if (Links == null || Links.length == 0) {
      link = null;
      return;
    }
    link = Links[0];

    ref = link.getDataReference();

    ShadowType shadow = link.getShadow().getAdaptedShadowType();
    MathType type = link.getType();

    if (type instanceof FunctionType) {
      if (shadow.getLevelOfDifficulty() != ShadowType.SIMPLE_FIELD) {
        whyNotDirect = notSimpleField;
        return;
      }
    }
    else {
      if (shadow.getLevelOfDifficulty() != ShadowType.SIMPLE_TUPLE) {
        whyNotDirect = notSimpleTuple;
        return;
      }
    }

    setIsDirectManipulation(true);
  }

  private int getDirectManifoldDimension() {
    return directManifoldDimension;
  }

  public String getWhyNotDirect() {
    return whyNotDirect;
  }

  public void addPoint(float[] x) throws VisADException {
    // may need to do this for performance
  }

// methods customized from DataRenderer:

  public CoordinateSystem getDisplayCoordinateSystem() {
    return null;
  }

  /** set spatialValues from ShadowType.doTransform */
  public synchronized void setSpatialValues(float[][] spatial_values) {
    // these are X, Y, Z values
    spatialValues = spatial_values;
  }

  /** check if ray intersects sub-manifold */
  public synchronized float checkClose(double[] origin, double[]
direction)
{
    int mouseModifiers = getLastMouseModifiers();
    if ((mouseModifiers & mouseModifiersMask) != mouseModifiersValue) {
      return Float.MAX_VALUE;
    }

    float distance = Float.MAX_VALUE;
    if (spatialValues == null) return distance;
    float o_x = (float) origin[0];
    float o_y = (float) origin[1];
    float o_z = (float) origin[2];
    float d_x = (float) direction[0];
    float d_y = (float) direction[1];
    float d_z = (float) direction[2];
 /*
System.out.println("origin = " + o_x + " " + o_y + " " + o_z);
System.out.println("direction = " + d_x + " " + d_y + " " + d_z);
  */
    for (int i=0; i<spatialValues[0].length; i++) {
      float x = spatialValues[0][i] - o_x;
      float y = spatialValues[1][i] - o_y;
      float z = spatialValues[2][i] - o_z;
      float dot = x * d_x + y * d_y + z * d_z;
      x = x - dot * d_x;
      y = y - dot * d_y;
      z = z - dot * d_z;
      float d = (float) Math.sqrt(x * x + y * y + z * z);
      if (d < distance) {
        distance = d;
        closeIndex = i;
      }
/*
System.out.println("spatialValues["+i+"] = " + spatialValues[0][i] + " "
+
spatialValues[1][i] + " " + spatialValues[2][i] + " d = " + d);
*/
    }
/*
System.out.println("checkClose: distance = " + distance);
*/
    return distance;
  }

  public int getCloseIndex() {
    return closeIndex;
  }

  public synchronized void drag_direct(VisADRay ray, boolean first,
                                       int mouseModifiers) {
    if (ref == null) return;

    if (first) {
      try {
        ref.setData(ref.getData());
      }
      catch (VisADException e) {
      }
      catch (RemoteException e) {
      }
    }
  }

  private static final int N = 64;

}