[Schmitzm-commits] r2290 - trunk/schmitzm-jfree/src/main/java/de/schmitzm/jfree/data

scm-commit at wald.intevation.org scm-commit at wald.intevation.org
Fri Mar 29 16:03:01 CET 2013


Author: mojays
Date: 2013-03-29 16:03:01 +0100 (Fri, 29 Mar 2013)
New Revision: 2290

Added:
   trunk/schmitzm-jfree/src/main/java/de/schmitzm/jfree/data/InterpolationTableXYDataset.java
   trunk/schmitzm-jfree/src/main/java/de/schmitzm/jfree/data/InterpolationXYSeries.java
   trunk/schmitzm-jfree/src/main/java/de/schmitzm/jfree/data/LinearInterpolationXYSeries.java
Log:
schmitzm-jfree: new InterpolationXYSeries and InterpolationTableXYDataset for automatic interpolation

Added: trunk/schmitzm-jfree/src/main/java/de/schmitzm/jfree/data/InterpolationTableXYDataset.java
===================================================================
--- trunk/schmitzm-jfree/src/main/java/de/schmitzm/jfree/data/InterpolationTableXYDataset.java	                        (rev 0)
+++ trunk/schmitzm-jfree/src/main/java/de/schmitzm/jfree/data/InterpolationTableXYDataset.java	2013-03-29 15:03:01 UTC (rev 2290)
@@ -0,0 +1,38 @@
+package de.schmitzm.jfree.data;
+
+import org.jfree.data.xy.DefaultTableXYDataset;
+import org.jfree.data.xy.XYDataItem;
+import org.jfree.data.xy.XYDataset;
+import org.jfree.data.xy.XYSeries;
+
+/**
+ * This {@link XYDataset} automatically interpolates an y-value if a series {@linkplain XYDataItem data item's}
+ * y-value is {@code null}. The interpolation is only provided when the respective series is
+ * a {@link InterpolationXYSeries}. 
+ * @see #getY(int, int)
+ * @author Martin O.J. Schmitz
+ *
+ */
+public class InterpolationTableXYDataset extends DefaultTableXYDataset {
+  
+  /**
+   * Returns the y-value for the specified series and item. If the y-value is not provided ({@code null})
+   * and the series is an {@link InterpolationXYSeries}, the y-value is interpolated.
+   *
+   * @param series  the series (zero-based index).
+   * @param index  the index of the item of interest (zero-based).
+   *
+   * @return The y-value for the specified series and item ({@code null} if the value can not
+   *         be interpolated)
+   */
+  @Override
+  public Number getY(int series, int index) {
+    Number y = super.getY(series, index);
+    if ( y == null ) {
+      XYSeries s = getSeries(series);
+      if ( s instanceof InterpolationXYSeries ) 
+        y = ((InterpolationXYSeries)s).getY(index,true);
+    }
+    return y;
+  }
+}
\ No newline at end of file

Added: trunk/schmitzm-jfree/src/main/java/de/schmitzm/jfree/data/InterpolationXYSeries.java
===================================================================
--- trunk/schmitzm-jfree/src/main/java/de/schmitzm/jfree/data/InterpolationXYSeries.java	                        (rev 0)
+++ trunk/schmitzm-jfree/src/main/java/de/schmitzm/jfree/data/InterpolationXYSeries.java	2013-03-29 15:03:01 UTC (rev 2290)
@@ -0,0 +1,215 @@
+package de.schmitzm.jfree.data;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.jfree.data.general.SeriesChangeEvent;
+import org.jfree.data.xy.XYDataItem;
+import org.jfree.data.xy.XYSeries;
+
+/**
+ * {@link XYSeries} which provides interpolation for data items with {@code null} y-values.
+ * This implementation holds an additional {@link TreeMap} of all data items with non-null
+ * y-values (ordered by x-value) which provides quick access to the next higher and next
+ * lower existing data item (for a given x-value).<br>
+ * Because of the use of a {@link Map} this {@link InterpolationXYSeries} does not
+ * allow duplicate x-values.
+ * @author Martin O.J. Schmitz
+ *
+ */
+public abstract class InterpolationXYSeries extends XYSeries {
+  /** Holds the data items of the series ordered by X-value to provide
+   *  fast access to next lower and next higher item.
+   *  @see #addOrUpdate(XYDataItem)
+   *  @see #getNextHigherItem(Number)
+   *  @see #getNextLowerItem(Number)
+   *  @see #getY(int, boolean)
+   */
+  protected TreeMap<Number, XYDataItem> tm = new TreeMap<Number,XYDataItem>();
+
+  /**
+   * Creates a new series.
+   * @param key  the series key (<code>null</code> not permitted).
+   * @param autoSort  a flag that controls whether or not the items in the
+   *                  series are sorted.
+   */
+  public InterpolationXYSeries(Comparable key, boolean autoSort) {
+    super(key, autoSort, false);
+  }
+
+  /** 
+   * Creates a new instance of {@link InterpolationXYSeries}, which is
+   * parameterized equal to {@code this} (key and autosort) instance.
+   * Used by {@link #clone()} and {@link #createCopy(int, int)}.
+   */
+  protected abstract InterpolationXYSeries newInstance();
+
+  /**
+   * Updates the {@link #tm TreeMap} for the given data item. If the item's
+   * y-value is {@code null} the item is removed from TreeMap. 
+   */
+  protected void updateTreeMap(XYDataItem item) {
+    final Number y = item.getY();
+    final Number x = item.getX();
+    if ( y == null )
+      tm.remove(x);
+    else 
+      tm.put(x, item);
+  }
+  
+  /**
+   * Returns the next higher data item for an X-value
+   * @param x an X-value
+   * @return {@code null} if there is there is no such item
+   */
+  public XYDataItem getNextHigherItem(Number x) {
+    final Number higherKey = tm.higherKey(x);
+    return higherKey != null ? tm.get( higherKey ) : null;
+  }
+
+  /**
+   * Returns the next lower data item for an X-value
+   * @param x an X-value
+   * @return {@code null} if there is there is no such item
+   */
+  public XYDataItem getNextLowerItem(Number x) {
+    final Number lowerKey = tm.lowerKey(x);
+    return lowerKey != null ? tm.get( lowerKey ) : null;
+  }
+  
+  /**
+   * Returns the y-value at the specified index. If current y-value is {@code null} and
+   * {@code interpolate} is set the y-value is calculated by linear interpolation
+   * between the next lower and the next higher x-values.
+   * @param index  the index (zero-based).
+   * @return The y-value (possibly <code>null</code>).
+   */
+  public Number getY(int index, boolean interpolate) {
+    Number y = super.getY(index);
+    if ( y == null && interpolate ) {
+      Number x          = getX(index);
+      XYDataItem lower  = getNextLowerItem(x);
+      XYDataItem higher = getNextHigherItem(x);
+      if ( lower != null && higher != null )
+        y = interpolate(x, lower, higher);
+    }
+    return y;
+  }
+  
+  /**
+   * Interpolates the y-value for the given x-value between the next lower and
+   * higher data items.
+   * @param x       x-value to interpolate the y-value for
+   * @param lower   data item of the next lower x value
+   * @param higher  data item of the next highter x value
+   */
+  protected abstract Number interpolate(Number x, XYDataItem lower, XYDataItem higher);
+  
+  ////////////////////////////////////////////////////////////////////////////
+  // Overridden Methods to pipe item maintenance to TreeMap
+  ////////////////////////////////////////////////////////////////////////////
+  /**
+   * Adds or updates an item in the series and sends a
+   * {@link SeriesChangeEvent} to all registered listeners.
+   * @param item  the data item (<code>null</code> not permitted).
+   * @return A copy of the overwritten data item, or <code>null</code> if no
+   *         item was overwritten.
+   */
+  public XYDataItem addOrUpdate(XYDataItem item) {
+    XYDataItem xyDataItem = super.addOrUpdate(item);
+    updateTreeMap(item);
+    return xyDataItem;
+  }
+
+  /**
+   * Adds a data item to the series and, if requested, sends a
+   * {@link SeriesChangeEvent} to all registered listeners.
+   *
+   * @param item  the (x, y) item (<code>null</code> not permitted).
+   * @param notify  a flag that controls whether or not a
+   *                {@link SeriesChangeEvent} is sent to all registered
+   *                listeners.
+   */
+   @Override
+  public void add(XYDataItem item, boolean notify) {
+    super.add(item, notify);
+    updateTreeMap(item);
+  }
+  
+  /**
+   * Removes the item at the specified index and sends a
+   * {@link SeriesChangeEvent} to all registered listeners.
+   * @param index  the index.
+   * @return The item removed.
+   */
+   @Override
+  public XYDataItem remove(int index) {
+    XYDataItem removed = super.remove(index);
+    if ( removed != null )
+      tm.remove(removed.getX());
+    return removed;
+  }
+  
+   /**
+    * Deletes a range of items from the series and sends a
+    * {@link SeriesChangeEvent} to all registered listeners.
+    *
+    * @param start  the start index (zero-based).
+    * @param end  the end index (zero-based).
+    */
+   @Override
+   public void delete(int start, int end) {
+     for (Object o : this.data.subList(start, end + 1))
+       tm.remove( ((XYDataItem)o).getX() );
+     super.delete(start, end);
+   }
+
+   /**
+    * Removes all data items from the series and sends a
+    * {@link SeriesChangeEvent} to all registered listeners.
+    */
+   @Override
+   public void clear() {
+     tm.clear();
+     super.clear();
+   }
+
+   /**
+    * Creates a new series by copying a subset of the data in this time series.
+    *
+    * @param start  the index of the first item to copy.
+    * @param end  the index of the last item to copy.
+    *
+    * @return A series containing a copy of this series from start until end.
+    *
+    * @throws CloneNotSupportedException if there is a cloning problem.
+    */
+   @Override
+   public InterpolationXYSeries createCopy(int start, int end) throws CloneNotSupportedException {
+     // Create (deep) copy of data items by super method
+     XYSeries copyData = ((XYSeries)super.createCopy(start, end));
+     // Add item clones to new InterpolationXYSeries
+     InterpolationXYSeries copy = newInstance();
+     for (Object item : copyData.getItems())
+       copy.add((XYDataItem)item);
+     return copy;
+   }
+
+   /**
+    * Returns a clone of the series.
+    *
+    * @return A clone of the series.
+    *
+    * @throws CloneNotSupportedException if there is a cloning problem.
+    */
+   @Override
+   public Object clone() throws CloneNotSupportedException {
+     // Create (deep) copy of data items by super method
+     XYSeries cloneData = (XYSeries) super.clone();
+     // Add item clones to new InterpolationXYSeries
+     InterpolationXYSeries clone = newInstance();
+     for (Object item : cloneData.getItems())
+       clone.add((XYDataItem)item);
+     return clone;
+   }
+}
\ No newline at end of file

Added: trunk/schmitzm-jfree/src/main/java/de/schmitzm/jfree/data/LinearInterpolationXYSeries.java
===================================================================
--- trunk/schmitzm-jfree/src/main/java/de/schmitzm/jfree/data/LinearInterpolationXYSeries.java	                        (rev 0)
+++ trunk/schmitzm-jfree/src/main/java/de/schmitzm/jfree/data/LinearInterpolationXYSeries.java	2013-03-29 15:03:01 UTC (rev 2290)
@@ -0,0 +1,51 @@
+package de.schmitzm.jfree.data;
+
+import java.util.TreeMap;
+
+import org.jfree.data.general.SeriesChangeEvent;
+import org.jfree.data.xy.XYDataItem;
+import org.jfree.data.xy.XYSeries;
+
+/**
+ * {@link XYSeries} which provides linear interpolation for data items
+ * with {@code null} y-values.
+ * @author Martin O.J. Schmitz
+ */
+public class LinearInterpolationXYSeries extends InterpolationXYSeries {
+  /**
+   * Creates a new series.
+   * @param key  the series key (<code>null</code> not permitted).
+   * @param autoSort  a flag that controls whether or not the items in the
+   *                  series are sorted.
+   */
+  public LinearInterpolationXYSeries(Comparable key, boolean autoSort) {
+    super(key, autoSort);
+  }
+
+  /** 
+   * Creates a new instance of {@link LinearInterpolationXYSeries}, which is
+   * parameterized equal to {@code this} (key and autosort) instance.
+   * Used by {@link #clone()} and {@link #createCopy(int, int)}.
+   */
+  @Override
+  protected LinearInterpolationXYSeries newInstance() {
+    return new LinearInterpolationXYSeries(getKey(), getAutoSort());
+  }
+
+  /**
+   * Interpolates the y-value for the given x-value between the next lower and
+   * higher data items in a linear way.
+   * @param x       x-value to interpolate the y-value for
+   * @param lower   data item of the next lower x value
+   * @param higher  data item of the next highter x value
+   * @return {@code lower.Y + dy * (x - lower.x) / dx}
+   */
+  @Override
+  protected Number interpolate(Number x, XYDataItem lower, XYDataItem higher) {
+    double dy = higher.getYValue() - lower.getYValue();
+    double dx = higher.getXValue() - lower.getXValue();
+    Number y = lower.getYValue() + dy * (x.doubleValue()-lower.getXValue())/dx;
+    
+    return y;
+  }
+}
\ No newline at end of file



More information about the Schmitzm-commits mailing list