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: * RendererUtilities.java
029: * ----------------------
030: * (C) Copyright 2007, by Object Refinery Limited.
031: *
032: * Original Author: David Gilbert (for Object Refinery Limited);
033: * Contributor(s): -;
034: *
035: * $Id: RendererUtilities.java,v 1.1.2.1 2007/05/04 11:12:16 mungady Exp $
036: *
037: * Changes
038: * -------
039: * 19-Apr-2007 : Version 1 (DG);
040: *
041: */
042:
043: package org.jfree.chart.renderer;
044:
045: import org.jfree.data.DomainOrder;
046: import org.jfree.data.xy.XYDataset;
047:
048: /**
049: * Utility methods related to the rendering process.
050: *
051: * @since 1.0.6
052: */
053: public class RendererUtilities {
054:
055: /**
056: * Finds the lower index of the range of live items in the specified data
057: * series.
058: *
059: * @param dataset the dataset (<code>null</code> not permitted).
060: * @param series the series index.
061: * @param xLow the lowest x-value in the live range.
062: * @param xHigh the highest x-value in the live range.
063: *
064: * @return The index of the required item.
065: *
066: * @since 1.0.6
067: *
068: * @see #findLiveItemsUpperBound(XYDataset, int, double, double)
069: */
070: public static int findLiveItemsLowerBound(XYDataset dataset,
071: int series, double xLow, double xHigh) {
072: int itemCount = dataset.getItemCount(series);
073: if (itemCount <= 1) {
074: return 0;
075: }
076: if (dataset.getDomainOrder() == DomainOrder.ASCENDING) {
077: // for data in ascending order by x-value, we are (broadly) looking
078: // for the index of the highest x-value that is less that xLow
079: int low = 0;
080: int high = itemCount - 1;
081: int mid = (low + high) / 2;
082: double lowValue = dataset.getXValue(series, low);
083: if (lowValue >= xLow) {
084: // special case where the lowest x-value is >= xLow
085: return low;
086: }
087: double highValue = dataset.getXValue(series, high);
088: if (highValue < xLow) {
089: // special case where the highest x-value is < xLow
090: return high;
091: }
092: while (high - low > 1) {
093: double midV = dataset.getXValue(series, mid);
094: if (midV >= xLow) {
095: high = mid;
096: } else {
097: low = mid;
098: }
099: mid = (low + high) / 2;
100: }
101: return mid;
102: } else if (dataset.getDomainOrder() == DomainOrder.DESCENDING) {
103: // when the x-values are sorted in descending order, the lower
104: // bound is found by calculating relative to the xHigh value
105: int low = 0;
106: int high = itemCount - 1;
107: int mid = (low + high) / 2;
108: double lowValue = dataset.getXValue(series, low);
109: if (lowValue <= xHigh) {
110: return low;
111: }
112: double highValue = dataset.getXValue(series, high);
113: if (highValue > xHigh) {
114: return high;
115: }
116: while (high - low > 1) {
117: double midV = dataset.getXValue(series, mid);
118: if (midV > xHigh) {
119: low = mid;
120: } else {
121: high = mid;
122: }
123: mid = (low + high) / 2;
124: }
125: return mid;
126: } else {
127: // we don't know anything about the ordering of the x-values,
128: // but we can still skip any initial values that fall outside the
129: // range...
130: int index = 0;
131: // skip any items that don't need including...
132: while (index < itemCount
133: && dataset.getXValue(series, index) < xLow) {
134: index++;
135: }
136: return Math.max(0, index - 1);
137: }
138: }
139:
140: /**
141: * Finds the index of the item in the specified series that...
142: *
143: * @param dataset the dataset (<code>null</code> not permitted).
144: * @param series the series index.
145: * @param xLow the lowest x-value in the live range.
146: * @param xHigh the highest x-value in the live range.
147: *
148: * @return The index of the required item.
149: *
150: * @since 1.0.6
151: *
152: * @see #findLiveItemsLowerBound(XYDataset, int, double, double)
153: */
154: public static int findLiveItemsUpperBound(XYDataset dataset,
155: int series, double xLow, double xHigh) {
156: int itemCount = dataset.getItemCount(series);
157: if (itemCount <= 1) {
158: return 0;
159: }
160: if (dataset.getDomainOrder() == DomainOrder.ASCENDING) {
161: int low = 0;
162: int high = itemCount - 1;
163: int mid = (low + high + 1) / 2;
164: double lowValue = dataset.getXValue(series, low);
165: if (lowValue > xHigh) {
166: return low;
167: }
168: double highValue = dataset.getXValue(series, high);
169: if (highValue <= xHigh) {
170: return high;
171: }
172: while (high - low > 1) {
173: double midV = dataset.getXValue(series, mid);
174: if (midV <= xHigh) {
175: low = mid;
176: } else {
177: high = mid;
178: }
179: mid = (low + high + 1) / 2;
180: }
181: return mid;
182: } else if (dataset.getDomainOrder() == DomainOrder.DESCENDING) {
183: // when the x-values are descending, the upper bound is found by
184: // comparing against xLow
185: int low = 0;
186: int high = itemCount - 1;
187: int mid = (low + high) / 2;
188: double lowValue = dataset.getXValue(series, low);
189: if (lowValue < xLow) {
190: return low;
191: }
192: double highValue = dataset.getXValue(series, high);
193: if (highValue >= xLow) {
194: return high;
195: }
196: while (high - low > 1) {
197: double midV = dataset.getXValue(series, mid);
198: if (midV >= xLow) {
199: low = mid;
200: } else {
201: high = mid;
202: }
203: mid = (low + high) / 2;
204: }
205: return mid;
206: } else {
207: // we don't know anything about the ordering of the x-values,
208: // but we can still skip any trailing values that fall outside the
209: // range...
210: int index = itemCount - 1;
211: // skip any items that don't need including...
212: while (index >= 0
213: && dataset.getXValue(series, index) > xHigh) {
214: index--;
215: }
216: return Math.min(itemCount - 1, index + 1);
217: }
218: }
219:
220: /**
221: * Finds a range of item indices that is guaranteed to contain all the
222: * x-values from x0 to x1 (inclusive).
223: *
224: * @param dataset the dataset (<code>null</code> not permitted).
225: * @param series the series index.
226: * @param xLow the lower bound of the x-value range.
227: * @param xHigh the upper bound of the x-value range.
228: *
229: * @return The indices of the boundary items.
230: */
231: public static int[] findLiveItems(XYDataset dataset, int series,
232: double xLow, double xHigh) {
233: // here we could probably be a little faster by searching for both
234: // indices simultaneously, but I'll look at that later if it seems
235: // like it matters...
236: int i0 = findLiveItemsLowerBound(dataset, series, xLow, xHigh);
237: int i1 = findLiveItemsUpperBound(dataset, series, xLow, xHigh);
238: return new int[] { i0, i1 };
239: }
240:
241: }
|