001 /* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2013 005 * Space Science and Engineering Center (SSEC) 006 * University of Wisconsin - Madison 007 * 1225 W. Dayton Street, Madison, WI 53706, USA 008 * https://www.ssec.wisc.edu/mcidas 009 * 010 * All Rights Reserved 011 * 012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and 013 * some McIDAS-V source code is based on IDV and VisAD source code. 014 * 015 * McIDAS-V is free software; you can redistribute it and/or modify 016 * it under the terms of the GNU Lesser Public License as published by 017 * the Free Software Foundation; either version 3 of the License, or 018 * (at your option) any later version. 019 * 020 * McIDAS-V is distributed in the hope that it will be useful, 021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 023 * GNU Lesser Public License for more details. 024 * 025 * You should have received a copy of the GNU Lesser Public License 026 * along with this program. If not, see http://www.gnu.org/licenses. 027 */ 028 029 // 030 // GrabLineRendererJ3D.java 031 // 032 033 package edu.wisc.ssec.mcidasv.data.hydra; 034 035 import java.rmi.RemoteException; 036 import java.util.Enumeration; 037 import java.util.Vector; 038 039 import visad.CommonUnit; 040 import visad.Data; 041 import visad.DataDisplayLink; 042 import visad.DataReference; 043 import visad.Display; 044 import visad.DisplayImpl; 045 import visad.DisplayRealType; 046 import visad.DisplayTupleType; 047 import visad.Gridded1DSet; 048 import visad.MathType; 049 import visad.Real; 050 import visad.RealTuple; 051 import visad.RealTupleType; 052 import visad.RealType; 053 import visad.ScalarMap; 054 import visad.ShadowRealType; 055 import visad.ShadowType; 056 import visad.Unit; 057 import visad.VisADException; 058 import visad.VisADRay; 059 060 /** 061 Grab and drag lines parallel to a coordinate axis. For simple 062 2D graphs, not yet generalized for 3D displays. For a 063 vertical line, map Real to Display.XAxis, and assign 064 ConstantMap for Display.YAxis. Vice-a-versa for a horizontal 065 line. 066 */ 067 068 public class GrabLineRendererJ3D extends visad.java3d.DirectManipulationRendererJ3D { 069 070 private float[][] spatialValues = null; 071 072 private int closeIndex = -1; 073 074 private float offsetx = 0.0f, offsety = 0.0f, offsetz = 0.0f; 075 private int offset_count = 0; 076 private static final int OFFSET_COUNT_INIT = 30; 077 078 private transient DataDisplayLink link = null; 079 private transient DataReference ref = null; 080 private transient MathType type = null; 081 private transient ShadowType shadow = null; 082 083 private float point_x, point_y, point_z; 084 private float line_x, line_y, line_z; 085 086 private float[] f = new float[1]; 087 private float[] d = new float[1]; 088 089 private String notRealType = "not RealType"; 090 private String whyNotDirect = null; 091 092 private boolean pickCrawlToCursor = true; 093 094 private int[] axisToComponent = {-1, -1, -1}; 095 private ScalarMap[] directMap = {null, null, null}; 096 097 private DisplayImpl display = null; 098 private DisplayTupleType tuple = null; 099 private boolean stop = false; 100 101 private Gridded1DSet domainSet = null; 102 private int last_idx = -1; 103 private float[][] samples = null; 104 105 private int mouseModifiersMask = 0; 106 private int mouseModifiersValue = 0; 107 108 public GrabLineRendererJ3D() { 109 this(null); 110 } 111 112 public GrabLineRendererJ3D(Gridded1DSet domainSet) { 113 super(); 114 this.domainSet = domainSet; 115 try { 116 if (domainSet != null) samples = domainSet.getSamples(); 117 } 118 catch (Exception e) { 119 System.out.println(e.getMessage()); 120 } 121 } 122 123 public String getWhyNotDirect() { 124 return whyNotDirect; 125 } 126 127 public synchronized void setSpatialValues(float[][] spatial_values) { 128 spatialValues = spatial_values; 129 } 130 131 public void checkDirect() throws VisADException, RemoteException { 132 setIsDirectManipulation(false); 133 134 display = getDisplay(); 135 link = getLinks()[0]; 136 ref = link.getDataReference(); 137 shadow = link.getShadow().getAdaptedShadowType(); 138 type = link.getType(); 139 if (!(type instanceof RealType)) { 140 whyNotDirect = notRealType; 141 return; 142 } 143 144 tuple = ((ShadowRealType) shadow).getDisplaySpatialTuple(); 145 146 //-ShadowRealType[] components = shadow.getRealComponents(); 147 ShadowRealType[] components = {(ShadowRealType)shadow}; 148 149 for (int i=0; i<components.length; i++) { 150 Enumeration maps = components[i].getSelectedMapVector().elements(); 151 while (maps.hasMoreElements()) { 152 ScalarMap map = (ScalarMap) maps.nextElement(); 153 DisplayRealType dreal = map.getDisplayScalar(); 154 DisplayTupleType tuple = dreal.getTuple(); 155 if (tuple != null && 156 (tuple.equals(Display.DisplaySpatialCartesianTuple) || 157 (tuple.getCoordinateSystem() != null && 158 tuple.getCoordinateSystem().getReference().equals( 159 Display.DisplaySpatialCartesianTuple)))) { 160 int index = dreal.getTupleIndex(); 161 axisToComponent[index] = i; 162 directMap[index] = map; 163 } 164 } // end while (maps.hasMoreElements()) 165 } 166 167 setIsDirectManipulation(true); 168 } 169 170 171 public synchronized float checkClose(double[] origin, double[] direction) 172 { 173 int mouseModifiers = getLastMouseModifiers(); 174 if ((mouseModifiers & mouseModifiersMask) != mouseModifiersValue) { 175 return Float.MAX_VALUE; 176 } 177 178 float distance = Float.MAX_VALUE; 179 if (display == null) return distance; 180 if (spatialValues == null) return distance; 181 float o_x = (float) origin[0]; 182 float o_y = (float) origin[1]; 183 float o_z = (float) origin[2]; 184 float d_x = (float) direction[0]; 185 float d_y = (float) direction[1]; 186 float d_z = (float) direction[2]; 187 /* 188 System.out.println("origin = " + o_x + " " + o_y + " " + o_z); 189 System.out.println("direction = " + d_x + " " + d_y + " " + d_z); 190 */ 191 192 for (int i=0; i<spatialValues[0].length; i++) { 193 float x = spatialValues[0][i] - o_x; 194 float y = spatialValues[1][i] - o_y; 195 float z = spatialValues[2][i] - o_z; 196 float dot = x * d_x + y * d_y + z * d_z; 197 x = x - dot * d_x; 198 y = y - dot * d_y; 199 z = z - dot * d_z; 200 float d = (float) Math.sqrt(x * x + y * y + z * z); 201 if (d < distance) { 202 distance = d; 203 closeIndex = i; 204 offsetx = x; 205 offsety = y; 206 offsetz = z; 207 } 208 /* 209 System.out.println("spatialValues["+i+"] = " + spatialValues[0][i] + " " + 210 spatialValues[1][i] + " " + spatialValues[2][i] + " d = " + d); 211 */ 212 } 213 214 float dist1D = Float.MAX_VALUE; 215 if (axisToComponent[0] != -1) dist1D = offsetx; 216 if (axisToComponent[1] != -1) dist1D = offsety; 217 if (axisToComponent[2] != -1) dist1D = offsetz; 218 return Math.abs(dist1D); 219 } 220 221 public synchronized void drag_direct(VisADRay ray, boolean first, 222 int mouseModifiers) { 223 if (display == null) return; 224 225 // disable printing of the cursor info string 226 getDisplayRenderer().setCursorStringOn(false); 227 228 // System.out.println("drag_direct " + first + " " + type); 229 if (spatialValues == null || ref == null || shadow == null || 230 link == null) return; 231 232 if (first) { 233 stop = false; 234 } 235 else { 236 if (stop) return; 237 } 238 239 float o_x = (float) ray.position[0]; 240 float o_y = (float) ray.position[1]; 241 float o_z = (float) ray.position[2]; 242 float d_x = (float) ray.vector[0]; 243 float d_y = (float) ray.vector[1]; 244 float d_z = (float) ray.vector[2]; 245 246 if (pickCrawlToCursor) { 247 if (first) { 248 offset_count = OFFSET_COUNT_INIT; 249 } 250 else { 251 if (offset_count > 0) offset_count--; 252 } 253 if (offset_count > 0) { 254 float mult = ((float) offset_count) / ((float) OFFSET_COUNT_INIT); 255 o_x += mult * offsetx; 256 o_y += mult * offsety; 257 o_z += mult * offsetz; 258 } 259 } 260 261 if (first) { 262 point_x = spatialValues[0][closeIndex]; 263 point_y = spatialValues[1][closeIndex]; 264 point_z = spatialValues[2][closeIndex]; 265 int lineAxis = -1; 266 for (int i=0; i<3; i++) { 267 if (getAxisToComponent(i) >= 0) { 268 lineAxis = i; 269 } 270 } 271 line_x = (lineAxis == 0) ? 1.0f : 0.0f; 272 line_y = (lineAxis == 1) ? 1.0f : 0.0f; 273 line_z = (lineAxis == 2) ? 1.0f : 0.0f; 274 } 275 float[] x = new float[3]; 276 277 // find closest point on line to ray 278 // logic from vis5d/cursor.c 279 // line o_, d_ to line point_, line_ 280 float ld = d_x * line_x + d_y * line_y + d_z * line_z; 281 float od = o_x * d_x + o_y * d_y + o_z * d_z; 282 float pd = point_x * d_x + point_y * d_y + point_z * d_z; 283 float ol = o_x * line_x + o_y * line_y + o_z * line_z; 284 float pl = point_x * line_x + point_y * line_y + point_z * line_z; 285 if (ld * ld == 1.0f) return; 286 float t = ((pl - ol) - (ld * (pd - od))) / (ld * ld - 1.0f); 287 // x is closest point 288 x[0] = point_x + t * line_x; 289 x[1] = point_y + t * line_y; 290 x[2] = point_z + t * line_z; 291 292 try { 293 float[] xx = {x[0], x[1], x[2]}; 294 if (tuple != null) { 295 /*- TDR ?? 296 float[][] cursor = {{x[0]}, {x[1]}, {x[2]}}; 297 float[][] new_cursor = 298 tuple.getCoordinateSystem().fromReference(cursor); 299 x[0] = new_cursor[0][0]; 300 x[1] = new_cursor[1][0]; 301 x[2] = new_cursor[2][0]; 302 */ 303 } 304 Data newData = null; 305 Data data; 306 try { 307 data = link.getData(); 308 } catch (RemoteException re) { 309 if (visad.collab.CollabUtil.isDisconnectException(re)) { 310 getDisplay().connectionFailed(this, link); 311 removeLink(link); 312 link = null; 313 return; 314 } 315 throw re; 316 } 317 int ii = -1; 318 RealType rtype = null; 319 if (type instanceof RealType) { 320 if (domainSet == null) addPoint(xx); 321 for (int i=0; i<3; i++) { 322 if (getAxisToComponent(i) >= 0) { 323 ii = i; 324 f[0] = x[i]; 325 d = getDirectMap(i).inverseScaleValues(f); 326 // RealType rtype = (RealType) data.getType(); 327 rtype = (RealType) type; 328 newData = new Real(rtype, (double) d[0], rtype.getDefaultUnit(), null); 329 break; 330 } 331 } 332 if (domainSet != null) { 333 int[] idx = domainSet.valueToIndex(new float[][] {d}); 334 if (idx[0] != last_idx && idx[0] >= 0) { 335 newData = new Real(rtype, (double)samples[0][idx[0]], rtype.getDefaultUnit(), null); 336 337 // create location string 338 Vector<String> vect = new Vector<String>(); 339 //-Real r = new Real(rtype, d[0]); 340 Real r = new Real(rtype, samples[0][idx[0]]); 341 Unit overrideUnit = getDirectMap(ii).getOverrideUnit(); 342 Unit rtunit = rtype.getDefaultUnit(); 343 // units not part of Time string 344 if (overrideUnit != null && !overrideUnit.equals(rtunit) && 345 (!Unit.canConvert(rtunit, CommonUnit.secondsSinceTheEpoch) || 346 rtunit.getAbsoluteUnit().equals(rtunit))) { 347 double dval = overrideUnit.toThis((double) d[0], rtunit); 348 r = new Real(rtype, dval, overrideUnit); 349 } 350 String valueString = r.toValueString(); 351 vect.addElement(rtype.getName() + " = " + valueString); 352 getDisplayRenderer().setCursorStringVector(vect); 353 354 ref.setData(newData); 355 link.clearData(); 356 last_idx = idx[0]; 357 } 358 } 359 else { 360 ref.setData(newData); 361 link.clearData(); 362 } 363 } 364 else if (type instanceof RealTupleType) { 365 addPoint(xx); 366 int n = ((RealTuple) data).getDimension(); 367 Real[] reals = new Real[n]; 368 Vector<String> vect = new Vector<String>(); 369 for (int i=0; i<3; i++) { 370 int j = getAxisToComponent(i); 371 if (j >= 0) { 372 f[0] = x[i]; 373 d = getDirectMap(i).inverseScaleValues(f); 374 Real c = (Real) ((RealTuple) data).getComponent(j); 375 rtype = (RealType) c.getType(); 376 reals[j] = new Real(rtype, (double) d[0], rtype.getDefaultUnit(), null); 377 } 378 } 379 getDisplayRenderer().setCursorStringVector(vect); 380 for (int j=0; j<n; j++) { 381 if (reals[j] == null) { 382 reals[j] = (Real) ((RealTuple) data).getComponent(j); 383 } 384 } 385 newData = new RealTuple((RealTupleType) type, reals, 386 ((RealTuple) data).getCoordinateSystem()); 387 //ref.setData(newData); 388 //link.clearData(); 389 390 if (domainSet != null) { 391 int[] idx = domainSet.valueToIndex(new float[][] {d}); 392 if (idx[0] != last_idx && idx[0] >= 0) { 393 newData = new Real(rtype, (double)samples[0][idx[0]], rtype.getDefaultUnit(), null); 394 395 // create location string 396 vect = new Vector<String>(); 397 //-Real r = new Real(rtype, d[0]); 398 Real r = new Real(rtype, samples[0][idx[0]]); 399 Unit overrideUnit = getDirectMap(ii).getOverrideUnit(); 400 Unit rtunit = rtype.getDefaultUnit(); 401 // units not part of Time string 402 if (overrideUnit != null && !overrideUnit.equals(rtunit) && 403 (!Unit.canConvert(rtunit, CommonUnit.secondsSinceTheEpoch) || 404 rtunit.getAbsoluteUnit().equals(rtunit))) { 405 double dval = overrideUnit.toThis((double) d[0], rtunit); 406 r = new Real(rtype, dval, overrideUnit); 407 } 408 String valueString = r.toValueString(); 409 vect.addElement(rtype.getName() + " = " + valueString); 410 getDisplayRenderer().setCursorStringVector(vect); 411 412 ref.setData(newData); 413 link.clearData(); 414 last_idx = idx[0]; 415 } 416 } 417 else { 418 ref.setData(newData); 419 link.clearData(); 420 } 421 422 } 423 424 } 425 catch (VisADException e) { 426 System.out.println("drag_direct " + e); 427 e.printStackTrace(); 428 } 429 catch (RemoteException e) { 430 System.out.println("drag_direct " + e); 431 e.printStackTrace(); 432 } 433 434 } 435 436 private int getAxisToComponent(int i) { 437 return axisToComponent[i]; 438 } 439 440 private ScalarMap getDirectMap(int i) { 441 return directMap[i]; 442 } 443 444 public void stop_direct() { 445 stop = true; 446 } 447 }