1 | /* |
---|
2 | * $Id: CartesianGraph.java,v 1.20 2003/08/22 23:02:31 dwd Exp $ |
---|
3 | * |
---|
4 | * This software is provided by NOAA for full, free and open release. It is |
---|
5 | * understood by the recipient/user that NOAA assumes no liability for any |
---|
6 | * errors contained in the code. Although this software is released without |
---|
7 | * conditions or restrictions in its use, it is expected that appropriate |
---|
8 | * credit be given to its author and to the National Oceanic and Atmospheric |
---|
9 | * Administration should the software be included by the recipient as an |
---|
10 | * element in other product development. |
---|
11 | */ |
---|
12 | |
---|
13 | package gov.noaa.pmel.sgt; |
---|
14 | |
---|
15 | import gov.noaa.pmel.sgt.dm.SGTData; |
---|
16 | |
---|
17 | import gov.noaa.pmel.util.GeoDate; |
---|
18 | import gov.noaa.pmel.util.Range2D; |
---|
19 | import gov.noaa.pmel.util.Point2D; |
---|
20 | import gov.noaa.pmel.util.Debug; |
---|
21 | import gov.noaa.pmel.util.SoTRange; |
---|
22 | import gov.noaa.pmel.util.SoTValue; |
---|
23 | import gov.noaa.pmel.util.SoTPoint; |
---|
24 | |
---|
25 | import java.util.Vector; |
---|
26 | import java.util.Enumeration; |
---|
27 | import java.awt.Graphics; |
---|
28 | import java.awt.Event; |
---|
29 | import java.awt.Rectangle; |
---|
30 | import java.awt.Point; |
---|
31 | import java.beans.PropertyChangeEvent; |
---|
32 | |
---|
33 | /** |
---|
34 | * The <code>CartesianGraph</code> provides the transformation from user to |
---|
35 | * physical coordinates. A Cartesian graph has |
---|
36 | * horizontal and vertical transforms, from user to physical |
---|
37 | * coordinates, that are independent. |
---|
38 | * For example, yp = f(yu) and xp = g(xu), where |
---|
39 | * f() and g() are the vertical and horizontal transformations. |
---|
40 | * Multiple horizontal and vertical, X and Y, axes can be associated with |
---|
41 | * a <code>CartesianGraph</code> and their mapping of user to physical |
---|
42 | * coordinates is based on the <code>AxisTransform</code>s used. |
---|
43 | * The <code>CartesianGraph</code> also provide the support for |
---|
44 | * the rendering of data. The specific renderer is chosen based on |
---|
45 | * the type of <code>SGTData</code> and the data <code>Attribute</code> used. |
---|
46 | * <p> |
---|
47 | * The following demonstrates how a <code>CartesianGraph</code> may be |
---|
48 | * used. |
---|
49 | * |
---|
50 | * <pre> |
---|
51 | * // Create a CartesianGraph and transforms. |
---|
52 | * |
---|
53 | * CartesianGraph graph; |
---|
54 | * LinearTransform xt, yt; |
---|
55 | * Range2D xPhysRange, xUserRange; |
---|
56 | * Range2D yPhysRange, yUserRange; |
---|
57 | * Point2D.Double origin; |
---|
58 | * |
---|
59 | * graph = new CartesianGraph("Point Graph"); |
---|
60 | * layer.setGraph(graph); |
---|
61 | * xt = new LinearTransform(xPhysRange, xUserRange); |
---|
62 | * yt = new LinearTransform(yPhysRange, yUserRange); |
---|
63 | * graph.setXTransform(xt); |
---|
64 | * graph.setYTransform(yt); |
---|
65 | * origin = new Point2D.Double(xUserRange.start, |
---|
66 | * yUserRange.start); |
---|
67 | * |
---|
68 | * // Create the bottom axis, set its range in user units |
---|
69 | * // and its origin. Add the axis to the graph. |
---|
70 | * |
---|
71 | * PlainAxis xbot; |
---|
72 | * |
---|
73 | * xbot = new PlainAxis("Botton Axis"); |
---|
74 | * xbot.setRangeU(xUserRange); |
---|
75 | * xbot.setLocationU(origin); |
---|
76 | * graph.addXAxis(xbot); |
---|
77 | * |
---|
78 | * // Create the left axis, set its range in user units |
---|
79 | * // and its origin. Add the axis to the graph. |
---|
80 | * |
---|
81 | * PlainAxis yleft; |
---|
82 | * |
---|
83 | * yleft = new PlainAxis("Left Axis"); |
---|
84 | * yleft.setRangeU(yUserRange); |
---|
85 | * yleft.setLocationU(origin); |
---|
86 | * graph.addYAxis(yleft); |
---|
87 | * |
---|
88 | * // Create a PointAttribute for the display of the |
---|
89 | * // Collection of points. The points will be marked |
---|
90 | * // with a red triangle and labelled at the NE corner |
---|
91 | * // in blue. |
---|
92 | * |
---|
93 | * PointAttribute pattr; |
---|
94 | * |
---|
95 | * pattr = new PointAttribute(10, Color.red); |
---|
96 | * |
---|
97 | * // Associate the attribute and the point Collection |
---|
98 | * // with the graph. |
---|
99 | * |
---|
100 | * graph.setData(col, pattr); |
---|
101 | * </pre> |
---|
102 | * |
---|
103 | * @author Donald Denbo |
---|
104 | * @version $Revision: 1.20 $, $Date: 2003/08/22 23:02:31 $ |
---|
105 | * @since 1.0 |
---|
106 | */ |
---|
107 | public class CartesianGraph extends Graph { |
---|
108 | /**@associates <b>Axis</b> |
---|
109 | * @supplierCardinality 0..* |
---|
110 | * @clientRole xAxis_ */ |
---|
111 | protected Vector xAxis_; |
---|
112 | /** @associates <b>Axis</b> |
---|
113 | * @clientRole yAxis_ |
---|
114 | * @supplierCardinality 0..* */ |
---|
115 | protected Vector yAxis_; |
---|
116 | /** @clientRole xTransform_ |
---|
117 | * @link aggregation |
---|
118 | * @undirected */ |
---|
119 | protected AxisTransform xTransform_; |
---|
120 | /** @clientRole tTransfrom_ |
---|
121 | * @link aggregation |
---|
122 | * @undirected */ |
---|
123 | protected AxisTransform yTransform_; |
---|
124 | protected boolean clipping_ = false; |
---|
125 | protected Range2D xClipRange_; |
---|
126 | protected Range2D yClipRange_; |
---|
127 | protected SoTRange.Time tClipRange_; |
---|
128 | /**@shapeType AggregationLink |
---|
129 | * @undirected |
---|
130 | * @clientCardinality 1 |
---|
131 | * @supplierCardinality 1 |
---|
132 | * @label renderer */ |
---|
133 | private CartesianRenderer renderer_; |
---|
134 | /** |
---|
135 | * Default constructor. |
---|
136 | */ |
---|
137 | public CartesianGraph() { |
---|
138 | this(""); |
---|
139 | } |
---|
140 | /** |
---|
141 | * <code>CartesianGraph</code> constructor. |
---|
142 | * Creates default unity transforms. |
---|
143 | * |
---|
144 | * @param id CartesianGraph identifier |
---|
145 | */ |
---|
146 | public CartesianGraph(String id) { |
---|
147 | this(id, new LinearTransform(0.0, 1.0, 0.0, 1.0), |
---|
148 | new LinearTransform(0.0, 1.0, 0.0, 1.0)); |
---|
149 | } |
---|
150 | /** |
---|
151 | * Create a new <code>CartesianGraph</code>. Sets the identifier |
---|
152 | * and sets the x and y transforms. |
---|
153 | * |
---|
154 | * @param id identifier |
---|
155 | * @param xt x transform |
---|
156 | * @param yt y transform |
---|
157 | */ |
---|
158 | public CartesianGraph(String id,AxisTransform xt,AxisTransform yt) { |
---|
159 | super(id); |
---|
160 | xAxis_ = new Vector(2,2); |
---|
161 | yAxis_ = new Vector(2,2); |
---|
162 | xTransform_ = xt; |
---|
163 | if(xTransform_ != null) xTransform_.addPropertyChangeListener(this); |
---|
164 | yTransform_ = yt; |
---|
165 | if(yTransform_ != null) yTransform_.addPropertyChangeListener(this); |
---|
166 | } |
---|
167 | /** |
---|
168 | * Create a copy of the <code>CartesianGraph</code> |
---|
169 | */ |
---|
170 | public Graph copy() { |
---|
171 | throw new MethodNotImplementedError(); |
---|
172 | } |
---|
173 | /** |
---|
174 | * Associates <code>SGTData</code> and <code>Attribute</code> with the |
---|
175 | * <code>CartesianGraph</code>. |
---|
176 | * A renderer is constucted based on the two arguements. |
---|
177 | * <p> |
---|
178 | * <TABLE BORDER="1" CELLPADDING="2" BGCOLOR="white"> |
---|
179 | * <TR> |
---|
180 | * <TH WIDTH="25%" BGCOLOR="#FFFFCC"> |
---|
181 | * <P>SGTData |
---|
182 | * </TH> |
---|
183 | * <TH WIDTH="25%" BGCOLOR="#FFFFCC"> |
---|
184 | * <P>Attribute |
---|
185 | * </TH> |
---|
186 | * <TH WIDTH="50%" BGCOLOR="#FFFFCC"> |
---|
187 | * <P>CartesianRenderer |
---|
188 | * </TH> |
---|
189 | * </TR> |
---|
190 | * <TR> |
---|
191 | * <TD WIDTH="25%">SGTPoint</TD> |
---|
192 | * <TD WIDTH="25%">PontAttribute</TD> |
---|
193 | * <TD WIDTH="50%">PointCartesianRenderer</TD> |
---|
194 | * </TR> |
---|
195 | * <TR> |
---|
196 | * <TD WIDTH="25%">SGTLine</TD> |
---|
197 | * <TD WIDTH="25%">LineAttribute</TD> |
---|
198 | * <TD WIDTH="50%">LineCartesianRenderer</TD> |
---|
199 | * </TR> |
---|
200 | * <TR> |
---|
201 | * <TD WIDTH="25%">SGTGrid</TD> |
---|
202 | * <TD WIDTH="25%">GridAttribute</TD> |
---|
203 | * <TD WIDTH="50%">GridCartesianRenderer</TD> |
---|
204 | * </TR> |
---|
205 | * <TR> |
---|
206 | * <TD WIDTH="25%">SGTVector</TD> |
---|
207 | * <TD WIDTH="25%">VectorAttribute</TD> |
---|
208 | * <TD WIDTH="50%">VectorCartesianRenderer</TD> |
---|
209 | * </TR> |
---|
210 | * <TR> |
---|
211 | * <TD WIDTH="25%">Collection</TD> |
---|
212 | * <TD WIDTH="25%">PointAttribute</TD> |
---|
213 | * <TD WIDTH="50%">PointCartesianRenderer</TD> |
---|
214 | * </TR> |
---|
215 | * <TR> |
---|
216 | * <TD WIDTH="25%">Collection</TD> |
---|
217 | * <TD WIDTH="25%">LineAttribute</TD> |
---|
218 | * <TD WIDTH="50%">LineCartesianRenderer</TD> |
---|
219 | * </TR> |
---|
220 | * <TR> |
---|
221 | * <TD WIDTH="25%">Collection</TD> |
---|
222 | * <TD WIDTH="25%">VectorAttribute</TD> |
---|
223 | * <TD WIDTH="50%">VectorCartesianRenderer</TD> |
---|
224 | * </TR> |
---|
225 | * <TR> |
---|
226 | * <TD WIDTH="25%">Annotation</TD> |
---|
227 | * <TD WIDTH="25%">n/a</TD> |
---|
228 | * <TD WIDTH="50%">AnnotationCartesianRenderer</TD> |
---|
229 | * </TR> |
---|
230 | *</TABLE> |
---|
231 | *<p> |
---|
232 | * @param data data to be rendered |
---|
233 | * @param attr rendering style information |
---|
234 | * @see CartesianRenderer#getRenderer |
---|
235 | */ |
---|
236 | public void setData(SGTData data, Attribute attr) { |
---|
237 | renderer_ = CartesianRenderer.getRenderer(this, data, attr); |
---|
238 | data.addPropertyChangeListener(this); |
---|
239 | } |
---|
240 | /** |
---|
241 | * Get the renderer instance being used by the graph. |
---|
242 | * |
---|
243 | * @return renderer |
---|
244 | */ |
---|
245 | public CartesianRenderer getRenderer() { |
---|
246 | return renderer_; |
---|
247 | } |
---|
248 | /** |
---|
249 | * Set the renderer used by the graph. |
---|
250 | * |
---|
251 | * @param rend a renderer object |
---|
252 | */ |
---|
253 | public void setRenderer(CartesianRenderer rend) { |
---|
254 | renderer_ = rend; |
---|
255 | } |
---|
256 | /** |
---|
257 | * Draw the graph, axes, and render the data. This method should |
---|
258 | * not be directly called. |
---|
259 | * |
---|
260 | * @see Pane#draw |
---|
261 | */ |
---|
262 | public void draw(Graphics g) { |
---|
263 | if(renderer_ != null) renderer_.draw(g); |
---|
264 | if(!xAxis_.isEmpty()) { |
---|
265 | for(Enumeration it = xAxis_.elements(); it.hasMoreElements();) { |
---|
266 | ((Axis)it.nextElement()).draw(g); |
---|
267 | } |
---|
268 | } |
---|
269 | if(!yAxis_.isEmpty()) { |
---|
270 | for(Enumeration it = yAxis_.elements(); it.hasMoreElements();) { |
---|
271 | ((Axis)it.nextElement()).draw(g); |
---|
272 | } |
---|
273 | } |
---|
274 | } |
---|
275 | /** |
---|
276 | * Set the clipping rectangle in user coordinates. |
---|
277 | * |
---|
278 | * @param xmin minimum horizontal coordinate |
---|
279 | * @param xmax maximum horizontal coordinate |
---|
280 | * @param ymin minimum vertical coordinate |
---|
281 | * @param ymax maximum vertical coordinate |
---|
282 | */ |
---|
283 | public void setClip(double xmin,double xmax,double ymin,double ymax) { |
---|
284 | if(xTransform_.isSpace() && yTransform_.isSpace()) { |
---|
285 | clipping_ = true; |
---|
286 | xClipRange_ = new Range2D(xmin, xmax); |
---|
287 | yClipRange_ = new Range2D(ymin, ymax); |
---|
288 | } else { |
---|
289 | clipping_ = false; |
---|
290 | } |
---|
291 | } |
---|
292 | /** |
---|
293 | * Set the clipping rectangle in user coordinates. |
---|
294 | * |
---|
295 | * @param tmin mimimum time |
---|
296 | * @param tmax maximum time |
---|
297 | * @param min miminum user coordinate |
---|
298 | * @param max maximum user coordinate |
---|
299 | */ |
---|
300 | public void setClip(GeoDate tmin, GeoDate tmax, double min, double max) { |
---|
301 | if(xTransform_.isTime() || yTransform_.isTime()) { |
---|
302 | clipping_ = true; |
---|
303 | tClipRange_ = new SoTRange.Time(tmin.getTime(), tmax.getTime()); |
---|
304 | if(xTransform_.isTime()) { |
---|
305 | yClipRange_ = new Range2D(min, max); |
---|
306 | } else { |
---|
307 | xClipRange_ = new Range2D(min, max); |
---|
308 | } |
---|
309 | } else { |
---|
310 | clipping_ = false; |
---|
311 | } |
---|
312 | } |
---|
313 | /** |
---|
314 | * Set the clipping rectangle in user coordinates. |
---|
315 | * |
---|
316 | * @since 3.0 |
---|
317 | * @param tmin mimimum time |
---|
318 | * @param tmax maximum time |
---|
319 | * @param min miminum user coordinate |
---|
320 | * @param max maximum user coordinate |
---|
321 | */ |
---|
322 | public void setClip(long tmin, long tmax, double min, double max) { |
---|
323 | if(xTransform_.isTime() || yTransform_.isTime()) { |
---|
324 | clipping_ = true; |
---|
325 | tClipRange_ = new SoTRange.Time(tmin, tmax); |
---|
326 | if(xTransform_.isTime()) { |
---|
327 | yClipRange_ = new Range2D(min, max); |
---|
328 | } else { |
---|
329 | xClipRange_ = new Range2D(min, max); |
---|
330 | } |
---|
331 | } else { |
---|
332 | clipping_ = false; |
---|
333 | } |
---|
334 | } |
---|
335 | /** |
---|
336 | * Set the clipping rectangle in user coordinates. |
---|
337 | * @since 2.0 |
---|
338 | */ |
---|
339 | public void setClip(SoTRange xr, SoTRange yr) { |
---|
340 | if(xr.isTime() || yr.isTime()) { |
---|
341 | SoTRange.Double dub; |
---|
342 | long tstart; |
---|
343 | long tend; |
---|
344 | if(xr.isTime()) { |
---|
345 | tstart = xr.getStart().getLongTime(); |
---|
346 | tend = xr.getEnd().getLongTime(); |
---|
347 | dub = (SoTRange.Double)yr; |
---|
348 | } else { |
---|
349 | tstart = yr.getStart().getLongTime(); |
---|
350 | tend = yr.getEnd().getLongTime(); |
---|
351 | dub = (SoTRange.Double)xr; |
---|
352 | } |
---|
353 | setClip(tstart, tend, dub.start, dub.end); |
---|
354 | } else { |
---|
355 | SoTRange.Double xrd = (SoTRange.Double)xr; |
---|
356 | SoTRange.Double yrd = (SoTRange.Double)yr; |
---|
357 | setClip(xrd.start, xrd.end, yrd.start, yrd.end); |
---|
358 | } |
---|
359 | } |
---|
360 | /** |
---|
361 | * Set the clipping property. |
---|
362 | * |
---|
363 | * @param clip clipping |
---|
364 | */ |
---|
365 | public void setClipping(boolean clip) { |
---|
366 | clipping_ = clip; |
---|
367 | } |
---|
368 | /** |
---|
369 | * Test the clipping property. |
---|
370 | * |
---|
371 | * @return true if clipping is active |
---|
372 | */ |
---|
373 | public boolean isClipping() { |
---|
374 | return clipping_; |
---|
375 | } |
---|
376 | /** |
---|
377 | * Add a X axis (<code>Axis.HORIZONTAL</code>) to the graph. |
---|
378 | * |
---|
379 | * @param id axis identifier |
---|
380 | * @param axis X axis |
---|
381 | * @see Axis |
---|
382 | * @see PlainAxis |
---|
383 | */ |
---|
384 | public void addXAxis(String id,Axis axis) { |
---|
385 | if(id.length() != 0) axis.setId(id); |
---|
386 | addXAxis(axis); |
---|
387 | } |
---|
388 | /** |
---|
389 | * Add a X axis (<code>Axis.HORIZONTAL</code>) to the graph. |
---|
390 | * Uses the existing axis identifier. |
---|
391 | * |
---|
392 | * @param axis X axis |
---|
393 | * @see Axis |
---|
394 | * @see PlainAxis |
---|
395 | */ |
---|
396 | public void addXAxis(Axis axis) { |
---|
397 | axis.setOrientation(Axis.HORIZONTAL); |
---|
398 | axis.setGraph(this); |
---|
399 | xAxis_.addElement(axis); |
---|
400 | } |
---|
401 | /** |
---|
402 | * Get a reference to an X axis. |
---|
403 | * |
---|
404 | * @param id axis identifier |
---|
405 | * @return axis found |
---|
406 | * @exception AxisNotFoundException An axis was not found with the correct identifier. |
---|
407 | * @see Axis |
---|
408 | * @see PlainAxis |
---|
409 | */ |
---|
410 | public Axis getXAxis(String id) throws AxisNotFoundException { |
---|
411 | if(!xAxis_.isEmpty()) { |
---|
412 | Axis ax; |
---|
413 | for(Enumeration it = xAxis_.elements(); it.hasMoreElements();) { |
---|
414 | ax = (Axis)it.nextElement(); |
---|
415 | if(ax.getId() == id) return ax; |
---|
416 | } |
---|
417 | throw new AxisNotFoundException(); |
---|
418 | } else { |
---|
419 | throw new AxisNotFoundException(); |
---|
420 | } |
---|
421 | } |
---|
422 | /** |
---|
423 | * Remove an X axis from the graph. |
---|
424 | * |
---|
425 | * @param id axis identifier |
---|
426 | * @exception AxisNotFoundException An axis was not found with the correct identifier. |
---|
427 | * @see Axis |
---|
428 | * @see PlainAxis |
---|
429 | */ |
---|
430 | public void removeXAxis(String id) throws AxisNotFoundException { |
---|
431 | if(!xAxis_.isEmpty()) { |
---|
432 | Axis ax; |
---|
433 | for(Enumeration it = xAxis_.elements(); it.hasMoreElements();) { |
---|
434 | ax = (Axis)it.nextElement(); |
---|
435 | if(ax.getId() == id) xAxis_.removeElement(ax); |
---|
436 | } |
---|
437 | throw new AxisNotFoundException(); |
---|
438 | } else { |
---|
439 | throw new AxisNotFoundException(); |
---|
440 | } |
---|
441 | } |
---|
442 | /** |
---|
443 | * Remove an X axis from the graph. |
---|
444 | * |
---|
445 | * @exception AxisNotFoundException An axis was not found with the correct identifier. |
---|
446 | * @see Axis |
---|
447 | * @see PlainAxis |
---|
448 | */ |
---|
449 | public void removeXAxis(Axis axis) throws AxisNotFoundException { |
---|
450 | if(!xAxis_.isEmpty()) { |
---|
451 | Axis ax; |
---|
452 | for(Enumeration it = xAxis_.elements(); it.hasMoreElements();) { |
---|
453 | ax = (Axis)it.nextElement(); |
---|
454 | if(ax.equals(axis)) xAxis_.removeElement(ax); |
---|
455 | } |
---|
456 | throw new AxisNotFoundException(); |
---|
457 | } else { |
---|
458 | throw new AxisNotFoundException(); |
---|
459 | } |
---|
460 | } |
---|
461 | /** |
---|
462 | * Remove all X axes from the graph. |
---|
463 | */ |
---|
464 | public void removeAllXAxes() { |
---|
465 | xAxis_.removeAllElements(); |
---|
466 | } |
---|
467 | /** |
---|
468 | * Get the number of X axes associated with the graph. |
---|
469 | * |
---|
470 | * @return number of axes |
---|
471 | * @see Axis |
---|
472 | * @see PlainAxis |
---|
473 | */ |
---|
474 | public int getNumberXAxis() { |
---|
475 | return xAxis_.size(); |
---|
476 | } |
---|
477 | /** |
---|
478 | * Get an <code>Enumeration</code> object for the X axes. |
---|
479 | * |
---|
480 | * @return enumeration |
---|
481 | */ |
---|
482 | public Enumeration xAxisElements() { |
---|
483 | return xAxis_.elements(); |
---|
484 | } |
---|
485 | /** |
---|
486 | * Add a Y axis (<code>Axis.VERTICAL</code>) to the graph. |
---|
487 | * |
---|
488 | * @param id axis identifier |
---|
489 | * @param axis Y axis |
---|
490 | * @see Axis |
---|
491 | * @see PlainAxis |
---|
492 | */ |
---|
493 | public void addYAxis(String id,Axis axis) { |
---|
494 | if(id.length() != 0) axis.setId(id); |
---|
495 | addYAxis(axis); |
---|
496 | } |
---|
497 | /** |
---|
498 | * Add a Y axis (<code>Axis.VERTICAL</code>) to the graph. |
---|
499 | * Uses the existing axis identifier. |
---|
500 | * |
---|
501 | * @param axis Y axis |
---|
502 | * @see Axis |
---|
503 | * @see PlainAxis |
---|
504 | */ |
---|
505 | public void addYAxis(Axis axis) { |
---|
506 | axis.setOrientation(Axis.VERTICAL); |
---|
507 | axis.setGraph(this); |
---|
508 | yAxis_.addElement(axis); |
---|
509 | } |
---|
510 | /** |
---|
511 | * Get a reference to an Y axis. |
---|
512 | * |
---|
513 | * @param id axis identifier |
---|
514 | * @return axis found |
---|
515 | * @exception AxisNotFoundException An axis was not found with the correct identifier. |
---|
516 | * @see Axis |
---|
517 | * @see PlainAxis |
---|
518 | */ |
---|
519 | public Axis getYAxis(String id) throws AxisNotFoundException { |
---|
520 | if(!yAxis_.isEmpty()) { |
---|
521 | Axis ax; |
---|
522 | for(Enumeration it = yAxis_.elements(); it.hasMoreElements();) { |
---|
523 | ax = (Axis)it.nextElement(); |
---|
524 | if(ax.getId() == id) return ax; |
---|
525 | } |
---|
526 | throw new AxisNotFoundException(); |
---|
527 | } else { |
---|
528 | throw new AxisNotFoundException(); |
---|
529 | } |
---|
530 | } |
---|
531 | /** |
---|
532 | * Remove an Y axis from the graph. |
---|
533 | * |
---|
534 | * @param id axis identifier |
---|
535 | * @exception AxisNotFoundException An axis was not found with the correct identifier. |
---|
536 | * @see Axis |
---|
537 | * @see PlainAxis |
---|
538 | */ |
---|
539 | public void removeYAxis(String id) throws AxisNotFoundException { |
---|
540 | if(!yAxis_.isEmpty()) { |
---|
541 | Axis ax; |
---|
542 | for(Enumeration it = yAxis_.elements(); it.hasMoreElements();) { |
---|
543 | ax = (Axis)it.nextElement(); |
---|
544 | if(ax.getId() == id) yAxis_.removeElement(ax); |
---|
545 | } |
---|
546 | throw new AxisNotFoundException(); |
---|
547 | } else { |
---|
548 | throw new AxisNotFoundException(); |
---|
549 | } |
---|
550 | } |
---|
551 | /** |
---|
552 | * Remove an Y axis from the graph. |
---|
553 | * |
---|
554 | * @exception AxisNotFoundException An axis was not found with the correct identifier. |
---|
555 | * @see Axis |
---|
556 | * @see PlainAxis |
---|
557 | */ |
---|
558 | public void removeYAxis(Axis axis) throws AxisNotFoundException { |
---|
559 | if(!yAxis_.isEmpty()) { |
---|
560 | Axis ax; |
---|
561 | for(Enumeration it = yAxis_.elements(); it.hasMoreElements();) { |
---|
562 | ax = (Axis)it.nextElement(); |
---|
563 | if(ax.equals(axis)) yAxis_.removeElement(ax); |
---|
564 | } |
---|
565 | throw new AxisNotFoundException(); |
---|
566 | } else { |
---|
567 | throw new AxisNotFoundException(); |
---|
568 | } |
---|
569 | } |
---|
570 | /** |
---|
571 | * Remove all Y axes from the graph. |
---|
572 | */ |
---|
573 | public void removeAllYAxes() { |
---|
574 | yAxis_.removeAllElements(); |
---|
575 | } |
---|
576 | /** |
---|
577 | * Get the number of Y axes associated with the graph. |
---|
578 | * |
---|
579 | * @return number of axes |
---|
580 | * @see Axis |
---|
581 | * @see PlainAxis |
---|
582 | */ |
---|
583 | public int getNumberYAxis() { |
---|
584 | return yAxis_.size(); |
---|
585 | } |
---|
586 | /** |
---|
587 | * Get an <code>Enumeration</code> object for the Y axes. |
---|
588 | * |
---|
589 | * @return enumeration |
---|
590 | */ |
---|
591 | public Enumeration yAxisElements() { |
---|
592 | return yAxis_.elements(); |
---|
593 | } |
---|
594 | /** |
---|
595 | * Set the X <code>AxisTransform</code>. This transform is used to convert |
---|
596 | * to and from user to physical coordinates. |
---|
597 | * |
---|
598 | * @param xfrm X transform |
---|
599 | * @see AxisTransform |
---|
600 | * @see LinearTransform |
---|
601 | */ |
---|
602 | public void setXTransform(AxisTransform xfrm) { |
---|
603 | if(xTransform_ != null) xTransform_.removePropertyChangeListener(this); |
---|
604 | xTransform_ = xfrm; |
---|
605 | xTransform_.addPropertyChangeListener(this); |
---|
606 | } |
---|
607 | /** |
---|
608 | * Get the current X <code>AxisTransform</code>. |
---|
609 | * |
---|
610 | * @return X Transform |
---|
611 | * @see AxisTransform |
---|
612 | * @see LinearTransform |
---|
613 | */ |
---|
614 | public AxisTransform getXTransform() { |
---|
615 | return xTransform_; |
---|
616 | } |
---|
617 | /** |
---|
618 | * Set the Y <code>AxisTransform</code>. This transform is used to convert |
---|
619 | * to and from user to physical coordinates. |
---|
620 | * |
---|
621 | * @param xfrm Y transform |
---|
622 | * @see AxisTransform |
---|
623 | * @see LinearTransform |
---|
624 | */ |
---|
625 | public void setYTransform(AxisTransform xfrm) { |
---|
626 | if(yTransform_ != null) yTransform_.removePropertyChangeListener(this); |
---|
627 | yTransform_ = xfrm; |
---|
628 | yTransform_.addPropertyChangeListener(this); |
---|
629 | } |
---|
630 | /** |
---|
631 | * Get the current Y <code>AxisTransform</code>. |
---|
632 | * |
---|
633 | * @return Y Transform |
---|
634 | * @see AxisTransform |
---|
635 | * @see LinearTransform |
---|
636 | */ |
---|
637 | public AxisTransform getYTransform() { |
---|
638 | return yTransform_; |
---|
639 | } |
---|
640 | // |
---|
641 | Object getObjectAt(Point pt) { |
---|
642 | Rectangle bnds; |
---|
643 | Axis ax; |
---|
644 | SGLabel lab; |
---|
645 | if(!xAxis_.isEmpty()) { |
---|
646 | for(Enumeration it = xAxis_.elements(); it.hasMoreElements();) { |
---|
647 | ax = (Axis)it.nextElement(); |
---|
648 | bnds = ax.getBounds(); |
---|
649 | if(bnds.contains(pt)) { |
---|
650 | return ax; |
---|
651 | } |
---|
652 | lab = ax.getTitle(); |
---|
653 | if((lab != null) && (lab.getLayer() != null)) { |
---|
654 | bnds = lab.getBounds(); |
---|
655 | if(bnds.contains(pt)) { |
---|
656 | return lab; |
---|
657 | } |
---|
658 | } |
---|
659 | } |
---|
660 | } |
---|
661 | if(!yAxis_.isEmpty()) { |
---|
662 | for(Enumeration it = yAxis_.elements(); it.hasMoreElements();) { |
---|
663 | ax = (Axis)it.nextElement(); |
---|
664 | bnds = ax.getBounds(); |
---|
665 | if(bnds.contains(pt)) { |
---|
666 | return ax; |
---|
667 | } |
---|
668 | lab = ax.getTitle(); |
---|
669 | if(lab != null) { |
---|
670 | bnds = lab.getBounds(); |
---|
671 | if(bnds.contains(pt)) { |
---|
672 | return lab; |
---|
673 | } |
---|
674 | } |
---|
675 | } |
---|
676 | } |
---|
677 | return (Object) null; |
---|
678 | } |
---|
679 | /** |
---|
680 | * Transform user X coordinate to physical coordinate. |
---|
681 | * @since 2.0 |
---|
682 | */ |
---|
683 | public double getXUtoP(double u) { |
---|
684 | return xTransform_.getTransP(u); |
---|
685 | } |
---|
686 | /** |
---|
687 | * Transform user X coordinate to device coordinate. |
---|
688 | * @since 2.0 |
---|
689 | */ |
---|
690 | public int getXUtoD(double u) { |
---|
691 | if(Double.isNaN(u)) return Integer.MIN_VALUE; |
---|
692 | return getLayer().getXPtoD(xTransform_.getTransP(u)); |
---|
693 | } |
---|
694 | /** |
---|
695 | * Transform user X coordinate to device coordinate. |
---|
696 | * @since 3.0 |
---|
697 | */ |
---|
698 | public double getXUtoD2(double u) { |
---|
699 | if(Double.isNaN(u)) return u; |
---|
700 | return getLayer().getXPtoD2(xTransform_.getTransP(u)); |
---|
701 | } |
---|
702 | /** |
---|
703 | * Transform <code>GeoDate</code> to physical coordinate. |
---|
704 | * @since 2.0 |
---|
705 | */ |
---|
706 | public double getXUtoP(GeoDate t) { |
---|
707 | return xTransform_.getTransP(t); |
---|
708 | } |
---|
709 | /** |
---|
710 | * Transform <code>long</code> to physical coordinate. |
---|
711 | * @since 3.0 |
---|
712 | */ |
---|
713 | public double getXUtoP(long t) { |
---|
714 | return xTransform_.getTransP(t); |
---|
715 | } |
---|
716 | /** |
---|
717 | * Transform <code>GeoDate</code> to device coordinate. |
---|
718 | * @since 2.0 |
---|
719 | */ |
---|
720 | public int getXUtoD(GeoDate t) { |
---|
721 | if(t == null) return Integer.MIN_VALUE; |
---|
722 | return getLayer().getXPtoD(xTransform_.getTransP(t)); |
---|
723 | } |
---|
724 | /** |
---|
725 | * Transform <code>long</code> to device coordinate. |
---|
726 | * @since 3.0 |
---|
727 | */ |
---|
728 | public int getXUtoD(long t) { |
---|
729 | if(t == Long.MAX_VALUE) return Integer.MIN_VALUE; |
---|
730 | return getLayer().getXPtoD(xTransform_.getTransP(t)); |
---|
731 | } |
---|
732 | /** |
---|
733 | * Transform <code>GeoDate</code> to device coordinate. |
---|
734 | * @since 3.0 |
---|
735 | */ |
---|
736 | public double getXUtoD2(GeoDate t) { |
---|
737 | if(t == null) return Double.NaN; |
---|
738 | return getLayer().getXPtoD2(xTransform_.getTransP(t)); |
---|
739 | } |
---|
740 | /** |
---|
741 | * Transform <code>long</code> to device coordinate. |
---|
742 | * @since 3.0 |
---|
743 | */ |
---|
744 | public double getXUtoD2(long t) { |
---|
745 | if(t == Long.MAX_VALUE) return Double.NaN; |
---|
746 | return getLayer().getXPtoD2(xTransform_.getTransP(t)); |
---|
747 | } |
---|
748 | /** |
---|
749 | * Transform X <code>SoTValue</code> to device coordinate. |
---|
750 | * @since 3.0 |
---|
751 | */ |
---|
752 | public int getXUtoD(SoTValue val) { |
---|
753 | if(val.isTime()) { |
---|
754 | return getXUtoD(val.getLongTime()); |
---|
755 | } else { |
---|
756 | return getXUtoD(((SoTValue.Double)val).getValue()); |
---|
757 | } |
---|
758 | } |
---|
759 | /** |
---|
760 | * Transform Y <code>SoTValue</code> to device coordinate. |
---|
761 | * @since 3.0 |
---|
762 | */ |
---|
763 | public int getYUtoD(SoTValue val) { |
---|
764 | if(val.isTime()) { |
---|
765 | return getYUtoD(val.getLongTime()); |
---|
766 | } else { |
---|
767 | return getYUtoD(((SoTValue.Double)val).getValue()); |
---|
768 | } |
---|
769 | } |
---|
770 | /** |
---|
771 | * Transform X <code>SoTValue</code> to device coordinate. |
---|
772 | * @since 3.0 |
---|
773 | */ |
---|
774 | public double getXUtoD2(SoTValue val) { |
---|
775 | if(val.isTime()) { |
---|
776 | return getXUtoD2(val.getLongTime()); |
---|
777 | } else { |
---|
778 | return getXUtoD2(((SoTValue.Double)val).getValue()); |
---|
779 | } |
---|
780 | } |
---|
781 | /** |
---|
782 | * Transform Y <code>SoTValue</code> to device coordinate. |
---|
783 | * @since 3.0 |
---|
784 | */ |
---|
785 | public double getYUtoD2(SoTValue val) { |
---|
786 | if(val.isTime()) { |
---|
787 | return getYUtoD2(val.getLongTime()); |
---|
788 | } else { |
---|
789 | return getYUtoD2(((SoTValue.Double)val).getValue()); |
---|
790 | } |
---|
791 | } |
---|
792 | /** |
---|
793 | * Transform X <code>SoTValue</code> to physical coordinate. |
---|
794 | * @since 3.0 |
---|
795 | */ |
---|
796 | public double getXUtoP(SoTValue val) { |
---|
797 | if(val.isTime()) { |
---|
798 | return getXUtoP(val.getLongTime()); |
---|
799 | } else { |
---|
800 | return getXUtoP(((SoTValue.Double)val).getValue()); |
---|
801 | } |
---|
802 | } |
---|
803 | /** |
---|
804 | * Transform Y <code>SoTValue</code> to physical coordinate. |
---|
805 | * @since 3.0 |
---|
806 | */ |
---|
807 | public double getYUtoP(SoTValue val) { |
---|
808 | if(val.isTime()) { |
---|
809 | return getYUtoP(val.getLongTime()); |
---|
810 | } else { |
---|
811 | return getYUtoP(((SoTValue.Double)val).getValue()); |
---|
812 | } |
---|
813 | } |
---|
814 | /** |
---|
815 | * Transform physical X coordinate to user coordinate using <code>SoTValue</code> |
---|
816 | * @param p physical coordinate |
---|
817 | * @return user coorindinate |
---|
818 | * @since 3.0 |
---|
819 | */ |
---|
820 | public SoTValue getXPtoSoT(double p) { |
---|
821 | if(xTransform_.isTime()) { |
---|
822 | return new SoTValue.Time(xTransform_.getLongTimeTransU(p)); |
---|
823 | } else { |
---|
824 | return new SoTValue.Double(xTransform_.getTransU(p)); |
---|
825 | } |
---|
826 | } |
---|
827 | /** |
---|
828 | * Transform physical X coordinate to user coordinate. |
---|
829 | * |
---|
830 | * @param p physical coorindate |
---|
831 | * @return user coordinate |
---|
832 | **/ |
---|
833 | public double getXPtoU(double p) { |
---|
834 | return xTransform_.getTransU(p); |
---|
835 | } |
---|
836 | /** |
---|
837 | * Transform physical X coordinate to time. |
---|
838 | * |
---|
839 | * @param p physical coordinate |
---|
840 | * @return time |
---|
841 | **/ |
---|
842 | public GeoDate getXPtoTime(double p) { |
---|
843 | return xTransform_.getTimeTransU(p); |
---|
844 | } |
---|
845 | /** |
---|
846 | * Transform physical X coordinate to time. |
---|
847 | * |
---|
848 | * @param p physical coordinate |
---|
849 | * @return time |
---|
850 | * @since 3.0 |
---|
851 | **/ |
---|
852 | public long getXPtoLongTime(double p) { |
---|
853 | return xTransform_.getLongTimeTransU(p); |
---|
854 | } |
---|
855 | /** |
---|
856 | * Transform physical coordinate to a <code>SoTPoint</code> |
---|
857 | * |
---|
858 | * @since 3.0 |
---|
859 | * @param p physical coordinate |
---|
860 | * @return <code>SoTPoint</code> |
---|
861 | **/ |
---|
862 | public SoTPoint getPtoU(Point2D.Double loc) { |
---|
863 | SoTValue xv; |
---|
864 | SoTValue yv; |
---|
865 | // x - transform |
---|
866 | if(xTransform_.isTime()) { |
---|
867 | xv = new SoTValue.Time(getXPtoLongTime(loc.x)); |
---|
868 | } else { |
---|
869 | xv = new SoTValue.Double(getXPtoU(loc.x)); |
---|
870 | } |
---|
871 | if(yTransform_.isTime()) { |
---|
872 | yv = new SoTValue.Time(getYPtoLongTime(loc.y)); |
---|
873 | } else { |
---|
874 | yv = new SoTValue.Double(getYPtoU(loc.y)); |
---|
875 | } |
---|
876 | return new SoTPoint(xv, yv); |
---|
877 | } |
---|
878 | /** |
---|
879 | * Transoform user Y coordinate to physical coordinate. |
---|
880 | * @since 2.0 |
---|
881 | */ |
---|
882 | public double getYUtoP(double u) { |
---|
883 | return yTransform_.getTransP(u); |
---|
884 | } |
---|
885 | /** |
---|
886 | * Transform user Y coordinate to device coordinate |
---|
887 | * @since 2.0 |
---|
888 | */ |
---|
889 | public int getYUtoD(double u) { |
---|
890 | if(Double.isNaN(u)) return Integer.MIN_VALUE; |
---|
891 | return getLayer().getYPtoD(yTransform_.getTransP(u)); |
---|
892 | } |
---|
893 | /** |
---|
894 | * Transform user Y coordinate to device coordinate |
---|
895 | * @since 3.0 |
---|
896 | */ |
---|
897 | public double getYUtoD2(double u) { |
---|
898 | if(Double.isNaN(u)) return u; |
---|
899 | return getLayer().getYPtoD2(yTransform_.getTransP(u)); |
---|
900 | } |
---|
901 | /** |
---|
902 | * Transform time to physical coordinate. |
---|
903 | * @since 2.0 |
---|
904 | */ |
---|
905 | public double getYUtoP(GeoDate t) { |
---|
906 | return yTransform_.getTransP(t); |
---|
907 | } |
---|
908 | /** |
---|
909 | * Transform time to physical coordinate. |
---|
910 | * @since 3.0 |
---|
911 | */ |
---|
912 | public double getYUtoP(long t) { |
---|
913 | if(t == Long.MAX_VALUE) return Double.NaN; |
---|
914 | return yTransform_.getTransP(t); |
---|
915 | } |
---|
916 | /** |
---|
917 | * Transform time to device coordinate. |
---|
918 | * @since 2.0 |
---|
919 | */ |
---|
920 | public int getYUtoD(GeoDate t) { |
---|
921 | if(t == null) return Integer.MIN_VALUE; |
---|
922 | return getLayer().getYPtoD(yTransform_.getTransP(t)); |
---|
923 | } |
---|
924 | /** |
---|
925 | * Transform time to device coordinate. |
---|
926 | * @since 3.0 |
---|
927 | */ |
---|
928 | public int getYUtoD(long t) { |
---|
929 | if(t == Long.MAX_VALUE) return Integer.MIN_VALUE; |
---|
930 | return getLayer().getYPtoD(yTransform_.getTransP(t)); |
---|
931 | } |
---|
932 | /** |
---|
933 | * Transform time to device coordinate. |
---|
934 | * @since 3.0 |
---|
935 | */ |
---|
936 | public double getYUtoD2(GeoDate t) { |
---|
937 | if(t == null) return Double.NaN; |
---|
938 | return getLayer().getYPtoD2(yTransform_.getTransP(t)); |
---|
939 | } |
---|
940 | /** |
---|
941 | * Transform time to device coordinate. |
---|
942 | * @since 3.0 |
---|
943 | */ |
---|
944 | public double getYUtoD2(long t) { |
---|
945 | if(t == Long.MAX_VALUE) return Double.NaN; |
---|
946 | return getLayer().getYPtoD2(yTransform_.getTransP(t)); |
---|
947 | } |
---|
948 | /** |
---|
949 | * Transform physical Y coordinate to user coordinate using <code>SoTValue</code> |
---|
950 | * @param p physical coordinate |
---|
951 | * @return user coorindinate |
---|
952 | * @since 3.0 |
---|
953 | */ |
---|
954 | public SoTValue getYPtoSoT(double p) { |
---|
955 | if(yTransform_.isTime()) { |
---|
956 | return new SoTValue.Time(yTransform_.getLongTimeTransU(p)); |
---|
957 | } else { |
---|
958 | return new SoTValue.Double(yTransform_.getTransU(p)); |
---|
959 | } |
---|
960 | } |
---|
961 | /** |
---|
962 | * Transform physical Y coordinate to user coordinate. |
---|
963 | * |
---|
964 | * @param p physical coorindate |
---|
965 | * @return user coordinate |
---|
966 | **/ |
---|
967 | public double getYPtoU(double p) { |
---|
968 | return yTransform_.getTransU(p); |
---|
969 | } |
---|
970 | /** |
---|
971 | * Transform physical Y coordinate to time. |
---|
972 | * |
---|
973 | * @param p physical coordinate |
---|
974 | * @return time |
---|
975 | **/ |
---|
976 | public GeoDate getYPtoTime(double p) { |
---|
977 | return yTransform_.getTimeTransU(p); |
---|
978 | } |
---|
979 | /** |
---|
980 | * Transform physical Y coordinate to time. |
---|
981 | * |
---|
982 | * @param p physical coordinate |
---|
983 | * @return time |
---|
984 | * @since 3.0 |
---|
985 | **/ |
---|
986 | public long getYPtoLongTime(double p) { |
---|
987 | return yTransform_.getLongTimeTransU(p); |
---|
988 | } |
---|
989 | |
---|
990 | public void propertyChange(PropertyChangeEvent evt) { |
---|
991 | // if(Debug.EVENT) { |
---|
992 | // System.out.println("CartesianGraph: " + evt); |
---|
993 | // System.out.println(" " + evt.getPropertyName()); |
---|
994 | // } |
---|
995 | modified("CartesianGraph: propertyChange(" + |
---|
996 | evt.getSource().toString() + "[" + |
---|
997 | evt.getPropertyName() + "]" + ")"); |
---|
998 | } |
---|
999 | /** |
---|
1000 | * Find data at point |
---|
1001 | * @since 3.0 |
---|
1002 | */ |
---|
1003 | public SGTData getDataAt(Point pt) { |
---|
1004 | return renderer_.getDataAt(pt); |
---|
1005 | } |
---|
1006 | } |
---|