[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