teichmann@5863: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde teichmann@5863: * Software engineering by Intevation GmbH teichmann@5863: * teichmann@5994: * This file is Free Software under the GNU AGPL (>=v3) teichmann@5863: * and comes with ABSOLUTELY NO WARRANTY! Check out the teichmann@5994: * documentation coming with Dive4Elements River for details. teichmann@5863: */ teichmann@5863: teichmann@5831: package org.dive4elements.river.exports; felix@1791: tom@9726: import org.apache.logging.log4j.Logger; tom@9726: import org.apache.logging.log4j.LogManager; felix@1791: felix@1791: import org.jfree.data.xy.XYSeries; felix@1791: teichmann@5831: import org.dive4elements.river.artifacts.model.WKms; teichmann@5831: import org.dive4elements.river.artifacts.model.WQKms; teichmann@5831: import org.dive4elements.river.artifacts.model.WWQQ; felix@1791: felix@1791: /** felix@1791: * Helper to create and modify StyledXYSeries. felix@1791: */ felix@1791: public class StyledSeriesBuilder { felix@1791: felix@2601: /** felix@2601: * JFreeChart and the area calculation will fail if we use Double.INFINITY felix@2601: * or Double.MAX_VALUE (probably because these are really used in felix@2601: * calculations). We define and use a more handy value instead. felix@2601: */ felix@2601: final static double BIG_DOUBLE_VALUE = 1234567d; felix@2601: tom@9726: private static final Logger log = LogManager.getLogger felix@2571: (StyledSeriesBuilder.class); felix@1791: felix@1791: felix@1791: /** felix@1791: * Trivial, hidden constructor. felix@1791: */ sascha@1886: private StyledSeriesBuilder() { sascha@1886: } felix@1791: felix@1791: felix@1791: /** tom@8856: * Add points to series, create gaps if certain distance tom@8856: * between points is met. felix@6212: * felix@6212: * @param series Series to add points to. felix@6212: * @param points Points to add to series, points[0] to 1st dim, points[1] felix@6212: * to 2nd dim. felix@6769: * @param skipNANs if true, skip NAN values in points parameter. Otherwise, felix@6769: * the NaNs lead to gaps in graph. felix@6212: * @param distance if two consecutive entries in points[0] are more tom@8856: * than distance apart, create a NaN value to skip tom@8856: * in display. felix@6212: */ tom@8856: public static void addPoints( tom@8856: XYSeries series, tom@8856: double[][] points, tom@8856: boolean skipNANs, tom@8856: double distance tom@8856: ) { felix@6212: if (points == null || points.length <= 1) { felix@6212: return; felix@6212: } felix@6212: double [] xPoints = points[0]; felix@6212: double [] yPoints = points[1]; felix@6212: for (int i = 0; i < xPoints.length; i++) { felix@6212: if (skipNANs && felix@6212: (Double.isNaN(xPoints[i]) || Double.isNaN(yPoints[i]))) { felix@6212: continue; felix@6212: } tom@8698: // Create gap if distance between points > distance. tom@8698: if (i > 0 && Math.abs(xPoints[i-1] - xPoints[i]) > distance && tom@8698: !Double.isNaN(yPoints[i-1]) && !Double.isNaN(yPoints[i])) { tom@8698: series.add((xPoints[i-1] + xPoints[i])/2, Double.NaN, false); felix@6212: } felix@6212: series.add(xPoints[i], yPoints[i], false); felix@6212: } felix@6212: } felix@6212: felix@6212: /** felix@1791: * Add points to series. felix@1791: * felix@1791: * @param series Series to add points to. felix@1791: * @param points Points to add to series, points[0] to 1st dim, points[1] felix@1791: * to 2nd dim. felix@2686: * @param skipNANs if true, skip NAN values in points parameter. felix@6465: * @param transY translate y-values by this value (before scale). felix@6465: * @param factorY scale y-values by this value (after translation). felix@6465: */ felix@6465: public static void addPoints(XYSeries series, double[][] points, felix@6465: boolean skipNANs, double transY, double factorY) { felix@6465: if (transY == 0d && factorY == 1d) { felix@6465: addPoints(series, points, skipNANs); felix@6465: return; felix@6465: } felix@6465: if (points == null || points.length <= 1) { felix@6465: return; felix@6465: } felix@6465: double [] xPoints = points[0]; felix@6465: double [] yPoints = points[1]; felix@6465: for (int i = 0; i < xPoints.length; i++) { felix@6465: if (skipNANs && felix@6465: (Double.isNaN(xPoints[i]) || Double.isNaN(yPoints[i]))) { felix@6465: continue; felix@6465: } felix@6465: series.add(xPoints[i], factorY * (transY+yPoints[i]), false); felix@6465: } felix@6465: } felix@6465: felix@6465: /** felix@6465: * Add points to series. felix@6465: * felix@6465: * @param series Series to add points to. felix@6465: * @param points Points to add to series, points[0] to 1st dim, points[1] felix@6465: * to 2nd dim. felix@6465: * @param skipNANs if true, skip NAN values in points parameter. felix@1791: */ tom@8856: public static void addPoints( tom@8856: XYSeries series, tom@8856: double[][] points, tom@8856: boolean skipNANs tom@8856: ) { felix@1983: if (points == null || points.length <= 1) { felix@1975: return; felix@1975: } felix@1791: double [] xPoints = points[0]; felix@1791: double [] yPoints = points[1]; felix@1791: for (int i = 0; i < xPoints.length; i++) { felix@2686: if (skipNANs && felix@2686: (Double.isNaN(xPoints[i]) || Double.isNaN(yPoints[i]))) { felix@2571: continue; felix@2571: } felix@1791: series.add(xPoints[i], yPoints[i], false); felix@1791: } felix@1791: } felix@1791: felix@1791: felix@1791: /** felix@1791: * Add points to series (km to 1st dim, w to 2nd dim). felix@1791: * felix@1791: * @param series Series to add points to. felix@3269: * @param wkms WKms to add to series. felix@1791: */ felix@1791: public static void addPoints(XYSeries series, WKms wkms) { felix@2156: if (wkms == null) { felix@2156: return; felix@2156: } felix@2156: felix@1791: int size = wkms.size(); felix@1791: felix@1791: for (int i = 0; i < size; i++) { felix@1791: series.add(wkms.getKm(i), wkms.getW(i), false); felix@1791: } felix@1791: } felix@1791: felix@3395: felix@3395: /** felix@3395: * Add points to dataset with an offset (shift all points by given amount). felix@3395: * @param series series to add data to. felix@3395: * @param wkms WKms of which the Ws will be shifted. felix@3395: * @param off the offset. felix@3395: */ felix@3394: public static void addUpperBand(XYSeries series, WKms wkms, double off) { felix@3394: if (wkms == null) { felix@3394: return; felix@3394: } felix@3394: felix@3394: int size = wkms.size(); felix@3394: felix@3394: for (int i = 0; i < size; i++) { felix@3394: series.add(wkms.getKm(i), wkms.getW(i)+off, false); felix@3394: } felix@3394: } felix@3394: felix@3395: felix@3395: /** felix@3395: * Add points to dataset with an offset (shift all points 'down' by given felix@3395: * amount). felix@3395: * @param series series to add data to. felix@3395: * @param wkms WKms of which the Ws will be shifted. felix@3395: * @param off the offset. felix@3395: */ felix@3394: public static void addLowerBand(XYSeries series, WKms wkms, double off) { felix@3394: addUpperBand(series, wkms, -off); felix@3394: } felix@1812: felix@3395: felix@1791: /** felix@1942: * Add points to series (km to 1st dim, q to 2nd dim). felix@1791: * felix@1791: * @param series Series to add points to. felix@3269: * @param wqkms WQKms to add to series. felix@1791: */ felix@1791: public static void addPointsKmQ(XYSeries series, WQKms wqkms) { felix@2156: if (wqkms == null) { felix@2156: return; felix@2156: } felix@1791: felix@2156: int size = wqkms.size(); felix@2156: felix@2156: for (int i = 0; i < size; i++) { felix@2156: series.add(wqkms.getKm(i), wqkms.getQ(i), false); felix@2156: } felix@1791: } felix@1812: felix@1812: felix@1812: /** felix@3176: * Add points to series (km to 1st dim, q to 2nd dim), adding points felix@3176: * to achieve a step-like curve. felix@3176: * felix@3176: * @param series Series to add points to. felix@3269: * @param wqkms WQKms to add to series. felix@3176: */ felix@3176: public static void addStepPointsKmQ(XYSeries series, WQKms wqkms) { felix@3176: if (wqkms == null) { felix@3176: return; felix@3176: } felix@3176: felix@3176: int size = wqkms.size(); felix@3176: felix@3176: for (int i = 0; i < size; i++) { felix@3176: if (i==0) { felix@3176: series.add(wqkms.getKm(i), wqkms.getQ(i), false); andre@8507: } else if (i == size-1) { andre@8507: series.add(wqkms.getKm(i), wqkms.getQ(i), false); andre@8507: } else { felix@3176: //Add two points. andre@8507: double prevX; andre@8507: double prevQ; andre@8507: if (wqkms.getKm(i + 1) < wqkms.getKm(i)) { andre@8507: /* Depending on the data direction the previous km / q tom@8856: * might have a larger index when we draw tom@8856: * right to left data. */ andre@8507: prevX = wqkms.getKm(i + 1); andre@8507: prevQ = wqkms.getQ(i + 1); andre@8507: } else { andre@8507: prevX = wqkms.getKm(i - 1); andre@8507: prevQ = wqkms.getQ(i - 1); andre@8507: } andre@8507: double halveX = (prevX + wqkms.getKm(i)) / 2d; andre@8507: series.add(halveX, prevQ, false); bjoern@4438: series.add(halveX, wqkms.getQ(i), false); felix@3176: } felix@3176: } felix@3176: } felix@3176: felix@3176: felix@3176: /** felix@1812: * Add points to series (q to 1st dim, w to 2nd dim). felix@1812: * felix@1812: * @param series Series to add points to. felix@3284: * @param wqkms WQKms to add to series. felix@1812: */ felix@1812: public static void addPointsQW(XYSeries series, WQKms wqkms) { felix@2156: if (wqkms == null) { felix@2156: return; felix@2156: } felix@2156: felix@1812: int size = wqkms.size(); felix@1812: felix@1812: for (int i = 0; i < size; i++) { bjoern@4438: series.add(wqkms.getQ(i), wqkms.getW(i), false); felix@1812: } felix@1812: } felix@2601: felix@6428: /** felix@6428: * Add points to series (q to 1st dim, w to 2nd dim), adding wTrans to the felix@6428: * W values and scaling it with wScale. felix@6428: * felix@6428: * @param series Series to add points to. felix@6881: * @param qws to add to series. felix@6881: * @param wAdd Value to add to each Q while adding to series. felix@6881: * @param wScale multiply with felix@6881: */ tom@8856: public static void addPointsQW( tom@8856: XYSeries series, tom@8856: double[][] qws, tom@8856: double wTrans, tom@8856: double wScale tom@8856: ) { felix@6881: if (qws == null || qws.length == 0) { felix@6881: return; felix@6881: } felix@6881: felix@6881: double x[] = qws[0]; felix@6881: double y[] = qws[1]; felix@6881: felix@6881: for (int i = 0; i < x.length; i++) { felix@6881: series.add(x[i], wScale * (y[i] + wTrans), false); felix@6881: } felix@6881: } felix@6881: /** felix@6881: * Add points to series (q to 1st dim, w to 2nd dim), adding wTrans to the felix@6881: * W values and scaling it with wScale. felix@6881: * felix@6881: * @param series Series to add points to. felix@6428: * @param wqkms WQKms to add to series. felix@6428: * @param wAdd Value to add to each Q while adding to series. felix@6428: * @param wScale multiply with felix@6428: */ tom@8856: public static void addPointsQW( tom@8856: XYSeries series, tom@8856: WQKms wqkms, tom@8856: double wTrans, tom@8856: double wScale tom@8856: ) { felix@6428: if (wqkms == null) { felix@6428: return; felix@6428: } felix@6428: felix@6428: int size = wqkms.size(); felix@6428: felix@6428: for (int i = 0; i < size; i++) { felix@6428: series.add(wqkms.getQ(i), wScale * (wqkms.getW(i) + wTrans), false); felix@6428: } felix@6428: } felix@2601: felix@2601: /** felix@2601: * Add points to series (q to 1st dim, w to 2nd dim). felix@2601: * felix@2601: * @param series Series to add points to. felix@4365: * @param qs the Qs to add, assumed same length than ws. felix@4365: * @param ws the Ws to add, assumed same length than qs. felix@4364: */ felix@4364: public static void addPointsQW(XYSeries series, double[] qs, double ws[]) { felix@4364: if (ws == null || qs == null) { felix@4364: return; felix@4364: } felix@4364: felix@4364: int size = qs.length; felix@4364: felix@4364: for (int i = 0; i < size; i++) { bjoern@4438: series.add(qs[i], ws[i], false); felix@4364: } felix@4364: } felix@4364: felix@6465: /** felix@6465: * Add points to series (q to 1st dim, w to 2nd dim), with felix@6465: * scaling and translation. felix@6465: * felix@6465: * @param series Series to add points to. felix@6465: * @param qs the Qs to add, assumed same length than ws. felix@6465: * @param ws the Ws to add, assumed same length than qs. felix@6465: */ felix@6465: public static void addPointsQW(XYSeries series, double[] qs, double ws[], felix@6465: double wTrans, double wScale) { felix@6465: if (ws == null || qs == null) { felix@6465: return; felix@6465: } felix@6465: felix@6465: int size = qs.length; felix@6465: felix@6465: for (int i = 0; i < size; i++) { felix@6465: series.add(qs[i], wScale * (ws[i]+wTrans), false); felix@6465: } felix@6465: } felix@6465: felix@6465: felix@4364: felix@4364: /** felix@4364: * Add points to series (q to 1st dim, w to 2nd dim). felix@4364: * felix@4364: * @param series Series to add points to. felix@3284: * @param wwqq WWQQ to add to series. felix@2601: */ felix@2601: public static void addPoints(XYSeries series, WWQQ wwqq) { felix@2601: if (wwqq == null) { felix@2601: return; felix@2601: } felix@2601: felix@2601: int size = wwqq.size(); felix@2601: felix@2601: for (int i = 0; i < size; i++) { bjoern@4438: series.add(wwqq.getW1(i), wwqq.getW2(i), false); felix@2601: } felix@2601: } felix@2601: felix@2601: felix@2601: /** felix@2601: * Create a Series such that an infinitely big area can be filled felix@2601: * between the newly created and the given series. felix@2601: */ felix@2601: public static XYSeries createGroundAtInfinity(XYSeries series) { tom@8856: XYSeries ground = tom@8856: new XYSeries(series.getKey() + /** TODO rand + */ "INF"); felix@2601: ground.add(series.getMinX(), -BIG_DOUBLE_VALUE); felix@2601: ground.add(series.getMaxX(), -BIG_DOUBLE_VALUE); felix@2601: return ground; felix@2601: } felix@2601: felix@2601: felix@2601: /** felix@2601: * Create a Series such that an infinitely big area can be filled felix@2601: * between the newly created and the given series. felix@2601: */ felix@2601: public static XYSeries createCeilingAtInfinity(XYSeries series) { tom@8856: XYSeries ground = tom@8856: new XYSeries(series.getKey() + /** TODO rand + */ "INF"); felix@2601: ground.add(series.getMinX(), BIG_DOUBLE_VALUE); felix@2601: ground.add(series.getMaxX(), BIG_DOUBLE_VALUE); felix@2601: return ground; felix@2601: } felix@1791: } felix@1791: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :