001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
006     *
007     * Project Info:  http://www.jfree.org/jfreechart/index.html
008     *
009     * This library is free software; you can redistribute it and/or modify it 
010     * under the terms of the GNU Lesser General Public License as published by 
011     * the Free Software Foundation; either version 2.1 of the License, or 
012     * (at your option) any later version.
013     *
014     * This library is distributed in the hope that it will be useful, but 
015     * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
016     * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
017     * License for more details.
018     *
019     * You should have received a copy of the GNU Lesser General Public
020     * License along with this library; if not, write to the Free Software
021     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
022     * USA.  
023     *
024     * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
025     * in the United States and other countries.]
026     *
027     * -------------------
028     * CrosshairState.java
029     * -------------------
030     * (C) Copyright 2002-2007, by Object Refinery Limited.
031     *
032     * Original Author:  David Gilbert (for Object Refinery Limited);
033     * Contributor(s):   -;
034     *
035     * Changes
036     * -------
037     * 24-Jan-2002 : Version 1 (DG);
038     * 05-Mar-2002 : Added Javadoc comments (DG);
039     * 26-Sep-2002 : Fixed errors reported by Checkstyle (DG);
040     * 19-Sep-2003 : Modified crosshair distance calculation (DG);
041     * 04-Dec-2003 : Crosshair anchor point now stored outside chart since it is
042     *               dependent on the display target (DG);
043     * 25-Feb-2004 : Replaced CrosshairInfo --> CrosshairState (DG);
044     * ------------- JFREECHART 1.0.x ---------------------------------------------
045     * 13-Oct-2006 : Fixed initialisation of CrosshairState - see bug report 
046     *               1565168 (DG);
047     * 06-Feb-2007 : Added new fields and methods to fix bug 1086307 (DG);
048     *
049     */
050    
051    package org.jfree.chart.plot;
052    
053    import java.awt.geom.Point2D;
054    
055    /**
056     * Maintains state information about crosshairs on a plot between successive 
057     * calls to the renderer's draw method.  This class is used internally by 
058     * JFreeChart - it is not intended for external use.
059     */
060    public class CrosshairState {
061    
062        /** 
063         * A flag that controls whether the distance is calculated in data space 
064         * or Java2D space.
065         */
066        private boolean calculateDistanceInDataSpace = false;
067    
068        /** The x-value (in data space) for the anchor point. */
069        private double anchorX;
070    
071        /** The y-value (in data space) for the anchor point. */
072        private double anchorY;
073        
074        /** The anchor point in Java2D space - if null, don't update crosshair. */
075        private Point2D anchor;
076        
077        /** The x-value for the current crosshair point. */
078        private double crosshairX;
079    
080        /** The y-value for the current crosshair point. */
081        private double crosshairY;
082    
083        /**
084         * The index of the domain axis that the crosshair x-value is measured
085         * against.
086         * 
087         * @since 1.0.4
088         */
089        private int domainAxisIndex;
090        
091        /**
092         * The index of the range axis that the crosshair y-value is measured
093         * against.
094         * 
095         * @since 1.0.4
096         */
097        private int rangeAxisIndex;
098        
099        /** 
100         * The smallest distance (so far) between the anchor point and a data 
101         * point. 
102         */
103        private double distance;
104    
105        /**
106         * Creates a new <code>CrosshairState</code> instance that calculates
107         * distance in Java2D space.
108         */
109        public CrosshairState() {
110            this(false);
111        }
112    
113        /**
114         * Creates a new <code>CrosshairState</code> instance.
115         * 
116         * @param calculateDistanceInDataSpace  a flag that controls whether the 
117         *                                      distance is calculated in data 
118         *                                      space or Java2D space.
119         */
120        public CrosshairState(boolean calculateDistanceInDataSpace) {
121            this.calculateDistanceInDataSpace = calculateDistanceInDataSpace;
122        }
123    
124        /**
125         * Returns the distance between the anchor point and the current crosshair
126         * point.
127         * 
128         * @return The distance.
129         * 
130         * @see #setCrosshairDistance(double)
131         * @since 1.0.3
132         */
133        public double getCrosshairDistance() {
134            return this.distance;
135        }
136        
137        /**
138         * Sets the distance between the anchor point and the current crosshair 
139         * point.  As each data point is processed, its distance to the anchor 
140         * point is compared with this value and, if it is closer, the data point 
141         * becomes the new crosshair point.
142         *
143         * @param distance  the distance.
144         * 
145         * @see #getCrosshairDistance()
146         */
147        public void setCrosshairDistance(double distance) {
148            this.distance = distance;
149        }
150    
151        /**
152         * Evaluates a data point and if it is the closest to the anchor point it
153         * becomes the new crosshair point.
154         * <P>
155         * To understand this method, you need to know the context in which it will
156         * be called.  An instance of this class is passed to an 
157         * {@link org.jfree.chart.renderer.xy.XYItemRenderer} as
158         * each data point is plotted.  As the point is plotted, it is passed to
159         * this method to see if it should be the new crosshair point.
160         *
161         * @param x  x coordinate (measured against the domain axis).
162         * @param y  y coordinate (measured against the range axis).
163         * @param transX  x translated into Java2D space.
164         * @param transY  y translated into Java2D space.
165         * @param orientation  the plot orientation.
166         * 
167         * @deprecated Use {@link #updateCrosshairPoint(double, double, int, int, 
168         *     double, double, PlotOrientation)}.  See bug report 1086307.
169         */
170        public void updateCrosshairPoint(double x, double y, 
171                                         double transX, double transY, 
172                                         PlotOrientation orientation) {
173            updateCrosshairPoint(x, y, 0, 0, transX, transY, orientation);
174        }
175        
176        /**
177         * Evaluates a data point and if it is the closest to the anchor point it
178         * becomes the new crosshair point.
179         * <P>
180         * To understand this method, you need to know the context in which it will
181         * be called.  An instance of this class is passed to an 
182         * {@link org.jfree.chart.renderer.xy.XYItemRenderer} as
183         * each data point is plotted.  As the point is plotted, it is passed to
184         * this method to see if it should be the new crosshair point.
185         *
186         * @param x  x coordinate (measured against the domain axis).
187         * @param y  y coordinate (measured against the range axis).
188         * @param domainAxisIndex  the index of the domain axis for this point.
189         * @param rangeAxisIndex  the index of the range axis for this point.
190         * @param transX  x translated into Java2D space.
191         * @param transY  y translated into Java2D space.
192         * @param orientation  the plot orientation.
193         * 
194         * @since 1.0.4
195         */
196        public void updateCrosshairPoint(double x, double y, int domainAxisIndex,
197                int rangeAxisIndex, double transX, double transY, 
198                PlotOrientation orientation) {
199    
200            if (this.anchor != null) {
201                double d = 0.0;
202                if (this.calculateDistanceInDataSpace) {
203                    d = (x - this.anchorX) * (x - this.anchorX)
204                      + (y - this.anchorY) * (y - this.anchorY);
205                }
206                else {
207                    double xx = this.anchor.getX();
208                    double yy = this.anchor.getY();
209                    if (orientation == PlotOrientation.HORIZONTAL) {
210                        double temp = yy;
211                        yy = xx;
212                        xx = temp;
213                    }
214                    d = (transX - xx) * (transX - xx) 
215                        + (transY - yy) * (transY - yy);            
216                }
217    
218                if (d < this.distance) {
219                    this.crosshairX = x;
220                    this.crosshairY = y;
221                    this.domainAxisIndex = domainAxisIndex;
222                    this.rangeAxisIndex = rangeAxisIndex;
223                    this.distance = d;
224                }
225            }
226    
227        }
228    
229        /**
230         * Evaluates an x-value and if it is the closest to the anchor x-value it
231         * becomes the new crosshair value.
232         * <P>
233         * Used in cases where only the x-axis is numerical.
234         *
235         * @param candidateX  x position of the candidate for the new crosshair 
236         *                    point.
237         *                    
238         * @deprecated Use {@link #updateCrosshairX(double, int)}.  See bug report 
239         *     1086307.
240         */
241        public void updateCrosshairX(double candidateX) {
242            updateCrosshairX(candidateX, 0);
243        }
244        
245        /**
246         * Evaluates an x-value and if it is the closest to the anchor x-value it
247         * becomes the new crosshair value.
248         * <P>
249         * Used in cases where only the x-axis is numerical.
250         *
251         * @param candidateX  x position of the candidate for the new crosshair 
252         *                    point.
253         * @param domainAxisIndex  the index of the domain axis for this x-value.
254         * 
255         * @since 1.0.4
256         */
257        public void updateCrosshairX(double candidateX, int domainAxisIndex) {
258    
259            double d = Math.abs(candidateX - this.anchorX);
260            if (d < this.distance) {
261                this.crosshairX = candidateX;
262                this.domainAxisIndex = domainAxisIndex;
263                this.distance = d;
264            }
265    
266        }
267    
268        /**
269         * Evaluates a y-value and if it is the closest to the anchor y-value it
270         * becomes the new crosshair value.
271         * <P>
272         * Used in cases where only the y-axis is numerical.
273         *
274         * @param candidateY  y position of the candidate for the new crosshair 
275         *                    point.
276         *                    
277         * @deprecated Use {@link #updateCrosshairY(double, int)}.  See bug report 
278         *     1086307.
279         */
280        public void updateCrosshairY(double candidateY) {
281            updateCrosshairY(candidateY, 0);
282        }
283    
284        /**
285         * Evaluates a y-value and if it is the closest to the anchor y-value it
286         * becomes the new crosshair value.
287         * <P>
288         * Used in cases where only the y-axis is numerical.
289         *
290         * @param candidateY  y position of the candidate for the new crosshair 
291         *                    point.
292         * @param rangeAxisIndex  the index of the range axis for this y-value.
293         * 
294         * @since 1.0.4
295         */
296        public void updateCrosshairY(double candidateY, int rangeAxisIndex) {
297            double d = Math.abs(candidateY - this.anchorY);
298            if (d < this.distance) {
299                this.crosshairY = candidateY;
300                this.rangeAxisIndex = rangeAxisIndex;
301                this.distance = d;
302            }
303    
304        }
305    
306        /**
307         * Returns the anchor point.
308         * 
309         * @return The anchor point.
310         * 
311         * @see #setAnchor(Point2D)
312         * @since 1.0.3
313         */
314        public Point2D getAnchor() {
315            return this.anchor;    
316        }
317        
318        /** 
319         * Sets the anchor point.  This is usually the mouse click point in a chart
320         * panel, and the crosshair point will often be the data item that is 
321         * closest to the anchor point.
322         * <br><br>
323         * Note that the x and y coordinates (in data space) are not updated by 
324         * this method - the caller is responsible for ensuring that this happens
325         * in sync.
326         * 
327         * @param anchor  the anchor point (<code>null</code> permitted).
328         * 
329         * @see #getAnchor()
330         */
331        public void setAnchor(Point2D anchor) {
332            this.anchor = anchor;
333        }
334        
335        /**
336         * Returns the x-coordinate (in data space) for the anchor point.
337         * 
338         * @return The x-coordinate of the anchor point.
339         * 
340         * @since 1.0.3
341         */
342        public double getAnchorX() {
343            return this.anchorX;    
344        }
345        
346        /**
347         * Sets the x-coordinate (in data space) for the anchor point.  Note that
348         * this does NOT update the anchor itself - the caller is responsible for
349         * ensuring this is done in sync.
350         * 
351         * @param x  the x-coordinate.
352         * 
353         * @since 1.0.3
354         */
355        public void setAnchorX(double x) {
356            this.anchorX = x;
357        }
358        
359        /**
360         * Returns the y-coordinate (in data space) for the anchor point.
361         * 
362         * @return The y-coordinate of teh anchor point.
363         * 
364         * @since 1.0.3
365         */
366        public double getAnchorY() {
367            return this.anchorY;    
368        }
369        
370        /**
371         * Sets the y-coordinate (in data space) for the anchor point.  Note that
372         * this does NOT update the anchor itself - the caller is responsible for
373         * ensuring this is done in sync.
374         * 
375         * @param y  the y-coordinate.
376         * 
377         * @since 1.0.3
378         */
379        public void setAnchorY(double y) {
380            this.anchorY = y;
381        }
382        
383        /**
384         * Get the x-value for the crosshair point.
385         *
386         * @return The x position of the crosshair point.
387         * 
388         * @see #setCrosshairX(double)
389         */
390        public double getCrosshairX() {
391            return this.crosshairX;
392        }
393        
394        /**
395         * Sets the x coordinate for the crosshair.  This is the coordinate in data
396         * space measured against the domain axis.
397         * 
398         * @param x the coordinate.
399         * 
400         * @see #getCrosshairX()
401         * @see #setCrosshairY(double)
402         * @see #updateCrosshairPoint(double, double, double, double, 
403         * PlotOrientation)
404         */
405        public void setCrosshairX(double x) {
406            this.crosshairX = x;
407        }
408    
409        /**
410         * Get the y-value for the crosshair point.  This is the coordinate in data
411         * space measured against the range axis.
412         *
413         * @return The y position of the crosshair point.
414         * 
415         * @see #setCrosshairY(double)
416         */
417        public double getCrosshairY() {
418            return this.crosshairY;
419        }
420    
421        /**
422         * Sets the y coordinate for the crosshair.
423         * 
424         * @param y  the y coordinate.
425         * 
426         * @see #getCrosshairY()
427         * @see #setCrosshairX(double)
428         * @see #updateCrosshairPoint(double, double, double, double, 
429         * PlotOrientation)
430         */
431        public void setCrosshairY(double y) {
432            this.crosshairY = y;
433        }
434        
435        /**
436         * Returns the domain axis index for the crosshair x-value.
437         * 
438         * @return The domain axis index.
439         * 
440         * @since 1.0.4
441         */
442        public int getDomainAxisIndex() {
443            return this.domainAxisIndex;
444        }
445    
446        /**
447         * Returns the range axis index for the crosshair y-value.
448         * 
449         * @return The range axis index.
450         * 
451         * @since 1.0.4
452         */
453        public int getRangeAxisIndex() {
454            return this.rangeAxisIndex;
455        }
456    }