Source for org.jfree.chart.renderer.RendererUtilities

   1: /* ===========================================================
   2:  * JFreeChart : a free chart library for the Java(tm) platform
   3:  * ===========================================================
   4:  *
   5:  * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
   6:  *
   7:  * Project Info:  http://www.jfree.org/jfreechart/index.html
   8:  *
   9:  * This library is free software; you can redistribute it and/or modify it 
  10:  * under the terms of the GNU Lesser General Public License as published by 
  11:  * the Free Software Foundation; either version 2.1 of the License, or 
  12:  * (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but 
  15:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  16:  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
  17:  * License for more details.
  18:  *
  19:  * You should have received a copy of the GNU Lesser General Public
  20:  * License along with this library; if not, write to the Free Software
  21:  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
  22:  * USA.  
  23:  *
  24:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
  25:  * in the United States and other countries.]
  26:  *
  27:  * ----------------------
  28:  * RendererUtilities.java
  29:  * ----------------------
  30:  * (C) Copyright 2007, by Object Refinery Limited.
  31:  *
  32:  * Original Author:  David Gilbert (for Object Refinery Limited);
  33:  * Contributor(s):   -;
  34:  *
  35:  * Changes
  36:  * -------
  37:  * 19-Apr-2007 : Version 1 (DG);
  38:  * 
  39:  */
  40: 
  41: package org.jfree.chart.renderer;
  42: 
  43: import org.jfree.data.DomainOrder;
  44: import org.jfree.data.xy.XYDataset;
  45: 
  46: /**
  47:  * Utility methods related to the rendering process.
  48:  * 
  49:  * @since 1.0.6
  50:  */
  51: public class RendererUtilities {
  52:     
  53:     /**
  54:      * Finds the lower index of the range of live items in the specified data
  55:      * series.  
  56:      * 
  57:      * @param dataset  the dataset (<code>null</code> not permitted).
  58:      * @param series  the series index.
  59:      * @param xLow  the lowest x-value in the live range.
  60:      * @param xHigh  the highest x-value in the live range.
  61:      * 
  62:      * @return The index of the required item.
  63:      * 
  64:      * @since 1.0.6
  65:      * 
  66:      * @see #findLiveItemsUpperBound(XYDataset, int, double, double)
  67:      */
  68:     public static int findLiveItemsLowerBound(XYDataset dataset, int series, 
  69:             double xLow, double xHigh) {
  70:         int itemCount = dataset.getItemCount(series);
  71:         if (itemCount <= 1) {
  72:             return 0;
  73:         }
  74:         if (dataset.getDomainOrder() == DomainOrder.ASCENDING) {
  75:             // for data in ascending order by x-value, we are (broadly) looking
  76:             // for the index of the highest x-value that is less that xLow
  77:             int low = 0;
  78:             int high = itemCount - 1;
  79:             int mid = (low + high) / 2;
  80:             double lowValue = dataset.getXValue(series, low);
  81:             if (lowValue >= xLow) {
  82:                 // special case where the lowest x-value is >= xLow
  83:                 return low;
  84:             }
  85:             double highValue = dataset.getXValue(series, high);
  86:             if (highValue < xLow) {
  87:                 // special case where the highest x-value is < xLow
  88:                 return high;
  89:             }
  90:             while (high - low > 1) {
  91:                 double midV = dataset.getXValue(series, mid);
  92:                 if (midV >= xLow) {
  93:                     high = mid;
  94:                 }
  95:                 else {
  96:                     low = mid;
  97:                 }
  98:                 mid = (low + high) / 2;
  99:             }
 100:             return mid;
 101:         }
 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:                 }
 121:                 else {
 122:                     high = mid;
 123:                 }
 124:                 mid = (low + high) / 2;
 125:             }
 126:             return mid;
 127:         }
 128:         else {
 129:             // we don't know anything about the ordering of the x-values,
 130:             // but we can still skip any initial values that fall outside the
 131:             // range...
 132:             int index = 0;
 133:             // skip any items that don't need including...
 134:             while (index < itemCount && dataset.getXValue(series, index) 
 135:                     < xLow) {
 136:                 index++;
 137:             }
 138:             return Math.max(0, index - 1);
 139:         }
 140:     }
 141:     
 142:     /**
 143:      * Finds the index of the item in the specified series that...
 144:      * 
 145:      * @param dataset  the dataset (<code>null</code> not permitted).
 146:      * @param series  the series index.
 147:      * @param xLow  the lowest x-value in the live range.
 148:      * @param xHigh  the highest x-value in the live range.
 149:      *
 150:      * @return The index of the required item.
 151:      * 
 152:      * @since 1.0.6
 153:      * 
 154:      * @see #findLiveItemsLowerBound(XYDataset, int, double, double)
 155:      */
 156:     public static int findLiveItemsUpperBound(XYDataset dataset, int series, 
 157:             double xLow, double xHigh) {
 158:         int itemCount = dataset.getItemCount(series);
 159:         if (itemCount <= 1) {
 160:             return 0;
 161:         }
 162:         if (dataset.getDomainOrder() == DomainOrder.ASCENDING) {
 163:             int low = 0;
 164:             int high = itemCount - 1;
 165:             int mid = (low + high + 1) / 2;
 166:             double lowValue = dataset.getXValue(series, low);
 167:             if (lowValue > xHigh) {
 168:                 return low;
 169:             }
 170:             double highValue = dataset.getXValue(series, high);
 171:             if (highValue <= xHigh) {
 172:                 return high;
 173:             }
 174:             while (high - low > 1) {
 175:                 double midV = dataset.getXValue(series, mid);
 176:                 if (midV <= xHigh) {
 177:                     low = mid;
 178:                 }
 179:                 else {
 180:                     high = mid;
 181:                 }
 182:                 mid = (low + high + 1) / 2;
 183:             }
 184:             return mid;
 185:         }
 186:         else if (dataset.getDomainOrder() == DomainOrder.DESCENDING) {
 187:             // when the x-values are descending, the upper bound is found by
 188:             // comparing against xLow
 189:             int low = 0;
 190:             int high = itemCount - 1;
 191:             int mid = (low + high) / 2;
 192:             double lowValue = dataset.getXValue(series, low);
 193:             if (lowValue < xLow) {
 194:                 return low;
 195:             }
 196:             double highValue = dataset.getXValue(series, high);
 197:             if (highValue >= xLow) {
 198:                 return high;
 199:             }
 200:             while (high - low > 1) {
 201:                 double midV = dataset.getXValue(series, mid);
 202:                 if (midV >= xLow) {
 203:                     low = mid;
 204:                 }
 205:                 else {
 206:                     high = mid;
 207:                 }
 208:                 mid = (low + high) / 2;
 209:             }
 210:             return mid;
 211:         }
 212:         else {
 213:             // we don't know anything about the ordering of the x-values,
 214:             // but we can still skip any trailing values that fall outside the
 215:             // range...
 216:             int index = itemCount - 1;
 217:             // skip any items that don't need including...
 218:             while (index >= 0 && dataset.getXValue(series, index) 
 219:                     > xHigh) {
 220:                 index--;
 221:             }
 222:             return Math.min(itemCount - 1, index + 1);
 223:         }
 224:     }
 225:     
 226:     /**
 227:      * Finds a range of item indices that is guaranteed to contain all the
 228:      * x-values from x0 to x1 (inclusive).
 229:      * 
 230:      * @param dataset  the dataset (<code>null</code> not permitted).
 231:      * @param series  the series index.
 232:      * @param xLow  the lower bound of the x-value range.
 233:      * @param xHigh  the upper bound of the x-value range.
 234:      * 
 235:      * @return The indices of the boundary items.
 236:      */
 237:     public static int[] findLiveItems(XYDataset dataset, int series, 
 238:             double xLow, double xHigh) {
 239:         // here we could probably be a little faster by searching for both
 240:         // indices simultaneously, but I'll look at that later if it seems
 241:         // like it matters...
 242:         int i0 = findLiveItemsLowerBound(dataset, series, xLow, xHigh);
 243:         int i1 = findLiveItemsUpperBound(dataset, series, xLow, xHigh);
 244:         return new int[] {i0, i1};
 245:     }
 246: 
 247: }