//
// DiscoverableZoom.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.bom;
import visad.*;
import visad.java3d.*;
import java.util.Vector;
import java.util.Enumeration;
import java.rmi.*;
/**
DiscoverableZoom is the VisAD class for
discoverable zoom of displayed data.
*/
public class DiscoverableZoom extends Object
implements ControlListener {
private boolean pfirst = true;
private double base_scale = 1.0;
private float last_cscale = 1.0f;
private float latmul, lonmul;
private DataRenderer[] renderers = null;
private boolean[] enabled = null;
private int nrenderers = -1;
private float[] lons = null;
private float[] lats = null;
/** the DataRenderers in the rs array are assumed to each link to
a Tuple data object that includes Real fields for Latitude and
Longitude, and that Latitude and Longitude are mapped to spatial
DisplayRealTypes; the DataRenderers in rs are enabled or disabled
to maintain a roughly constant spacing among their visible
depictions;
distance is the scale for distance;
in order to work, this DiscoverableZoom must be added as a
Control Listener to the ProjectionControl of the DisplayImpl
linked to the DataRenderer array rs;
see CollectiveBarbManipulation.java for an example of use */
public void setRenderers(DataRenderer[] rs, float distance)
throws VisADException, RemoteException {
renderers = rs;
if (renderers != null) {
nrenderers = renderers.length;
if (nrenderers == 0) {
nrenderers = -1;
return;
}
lons = new float[nrenderers];
lats = new float[nrenderers];
enabled = new boolean[nrenderers];
for (int i=0; i<nrenderers; i++) {
lons[i] = Float.NaN;
lats[i] = Float.NaN;
enabled[i] = true;
DataDisplayLink[] links = renderers[i].getLinks();
if (links == null || links.length == 0) continue;
Data data = links[0].getData();
if (data == null || !(data instanceof Tuple)) continue;
Real[] reals = ((Tuple) data).getRealComponents();
if (reals == null || reals.length == 0) continue;
for (int j=0; j<reals.length; j++) {
if (RealType.Latitude.equals(reals[j].getType())) {
lats[i] = (float) reals[j].getValue();
}
else if (RealType.Longitude.equals(reals[j].getType())) {
lons[i] = (float) reals[j].getValue();
}
}
if (lats[i] != lats[i] || lons[i] != lons[i]) {
lons[i] = Float.NaN;
lats[i] = Float.NaN;
}
}
DisplayImpl display = renderers[0].getDisplay();
if (display == null) {
nrenderers = -1;
return;
}
ScalarMap latmap = null;
ScalarMap lonmap = null;
Vector mapVector = display.getMapVector();
Enumeration maps = mapVector.elements();
while (maps.hasMoreElements()) {
ScalarMap map = (ScalarMap) maps.nextElement();
ScalarType real = map.getScalar();
DisplayRealType dreal = map.getDisplayScalar();
DisplayTupleType rtuple = dreal.getTuple();
if (rtuple != null) {
if (rtuple.equals(Display.DisplaySpatialCartesianTuple) ||
(rtuple.getCoordinateSystem() != null &&
rtuple.getCoordinateSystem().getReference().equals(
Display.DisplaySpatialCartesianTuple))) {
// dreal is spatial
if (RealType.Latitude.equals(real)) {
latmap = map;
}
else if (RealType.Longitude.equals(real)) {
lonmap = map;
}
}
}
} // end while (maps.hasMoreElements())
if (latmap == null || lonmap == null) {
nrenderers = -1;
return;
}
double[] latrange = latmap.getRange();
double[] lonrange = lonmap.getRange();
latmul = (float) (1.0 / (Math.abs(latrange[1] - latrange[0]) * distance));
lonmul = (float) (1.0 / (Math.abs(lonrange[1] - lonrange[0]) * distance));
if (latmul != latmul || lonmul != lonmul) {
nrenderers = -1;
return;
}
}
else { // renderers == null
nrenderers = -1;
return;
}
}
public void controlChanged(ControlEvent e)
throws VisADException, RemoteException {
ProjectionControl pcontrol = (ProjectionControl) e.getControl();
double[] matrix = pcontrol.getMatrix();
double[] rot = new double[3];
double[] scale = new double[1];
double[] trans = new double[3];
MouseBehaviorJ3D.unmake_matrix(rot, scale, trans, matrix);
if (pfirst) {
pfirst = false;
base_scale = scale[0];
last_cscale = 1.0f;
}
else {
if (nrenderers < 0) return;
float cscale = (float) (base_scale / scale[0]);
float ratio = cscale / last_cscale;
if (ratio < 0.95f || 1.05f < ratio) {
// System.out.println(latmul + " " + lonmul + " " + cscale);
last_cscale = cscale;
for (int i=0; i<nrenderers; i++) {
boolean enable = true;
if (lats[i] == lats[i] && lons[i] == lons[i]) {
for (int j=0; j<i; j++) {
if (enabled[j] && lats[j] == lats[j] && lons[j] == lons[j]) {
float latd = latmul * (lats[j] - lats[i]) / cscale;
float lond = lonmul * (lons[j] - lons[i]) / cscale;
float distsq = (latd * latd + lond * lond);
// System.out.println(i + " " + lats[i] + " " + lons[i] + " " +
// j + " " + lats[j] + " " + lons[j] + " " +
// latd + " " + lond + " " + distsq);
if (distsq < 1.0f) {
enable = false;
break;
}
}
}
}
// System.out.println("enabled[" + i + "] = " + enable);
enabled[i] = enable;
renderers[i].toggle(enable);
}
}
}
}
}