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 }