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