com.bdb.weather.display.freeplot.HistoricalFreePlot.java Source code

Java tutorial

Introduction

Here is the source code for com.bdb.weather.display.freeplot.HistoricalFreePlot.java

Source

/* 
 * Copyright (C) 2016 Bruce Beisel
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.bdb.weather.display.freeplot;

import java.awt.Color;
import java.awt.Stroke;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAccessor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Function;

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Parent;

import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.DefaultXYItemRenderer;
import org.jfree.data.time.Minute;

import com.bdb.util.jdbc.DBConnection;

import com.bdb.weather.common.HistoricalRecord;
import com.bdb.weather.common.Sensor;
import com.bdb.weather.common.SensorType;
import com.bdb.weather.common.WeatherStation;
import com.bdb.weather.common.db.HistoryTable;
import com.bdb.weather.common.measurement.Depth;
import com.bdb.weather.common.measurement.Humidity;
import com.bdb.weather.common.measurement.Pressure;
import com.bdb.weather.common.measurement.SolarRadiation;
import com.bdb.weather.common.measurement.Speed;
import com.bdb.weather.common.measurement.Temperature;
import com.bdb.weather.display.StageUtilities;
import com.bdb.weather.display.WeatherSenseConstants;
import com.bdb.weather.display.axis.HumidityRangeAxis;
import com.bdb.weather.display.axis.PressureRangeAxis;
import com.bdb.weather.display.axis.RainRangeAxis;
import com.bdb.weather.display.axis.SolarRadiationAxis;
import com.bdb.weather.display.axis.TemperatureRangeAxis;
import com.bdb.weather.display.axis.UvIndexAxis;
import com.bdb.weather.display.axis.WindSpeedRangeAxis;
import com.bdb.weather.display.freeplot.FreePlot.SeriesCollectionFactory;
import com.bdb.weather.display.freeplot.FreePlotSeriesCollection.SeriesFactory;
import com.bdb.weather.display.preferences.ColorPreferences;

/**
 * Class to plot historical records (the smallest data).
 * 
 * @author Bruce
 */
public class HistoricalFreePlot implements SeriesFactory, SeriesCollectionFactory {
    private static final String TEMPERATURE_COLLECTION_NAME = "Temperature";
    private static final String HUMIDITY_COLLECTION_NAME = "Humidity";
    private static final String PRESSURE_COLLECTION_NAME = "Pressure";
    private static final String WIND_COLLECTION_NAME = "Wind";
    private static final String RAIN_COLLECTION_NAME = "Rain";
    private static final String SOLAR_RADIATION_COLLECTION_NAME = "Solar Radiation";
    private static final String UV_INDEX_COLLECTION_NAME = "UV Index";
    private static final int NUM_COLLECTIONS = 7;

    private static final String OUTDOOR_TEMPERATURE_SERIES_NAME = "Outdoor Temperature";
    private static final String INDOOR_TEMPERATURE_SERIES_NAME = "Indoor Temperature";
    private static final String OUTDOOR_HUMIDITY_SERIES_NAME = "Outdoor Humidity";
    private static final String INDOOR_HUMIDITY_SERIES_NAME = "Indoor Humidity";
    private static final String DEW_POINT_SERIES_NAME = "Dew Point";
    private static final String HEAT_INDEX_SERIES_NAME = "Heat Index";
    private static final String WIND_CHILL_SERIES_NAME = "Wind Chill";
    private static final String SUSTAINED_WIND_SERIES_NAME = "Sustained Wind";
    private static final String HIGH_WIND_SERIES_NAME = "High Wind";
    private static final String WIND_GUST_SERIES_NAME = "Wind Gust";
    private static final String RAIN_SERIES_NAME = "Rainfall";
    private static final String HIGH_RAIN_RATE_SERIES_NAME = "High Rainfall Rate";
    private static final String BAROMETRIC_PRESSURE_SERIES_NAME = "Barometric Pressure";

    private static final String SOLAR_RADIATION_SERIES_NAME = "Solar Radiation";
    private static final String UV_INDEX_SERIES_NAME = "UV Index";

    private static final Class<?> INTERVAL_CLASS = Minute.class;

    private final FreePlot freePlot;
    private final HistoryTable table;
    private final WeatherStation ws;

    /**
     * Constructor.
     * 
     * @param ws The weather station
     * @param connection The connection to the database
     */
    public HistoricalFreePlot(WeatherStation ws, DBConnection connection) {
        this.ws = ws;
        freePlot = new FreePlot(this);
        table = new HistoryTable(connection);
    }

    /**
     * Return the JavaFX node that is the container for this plot.
     * 
     * @return The JavaFX Node
     */
    public Parent getNode() {
        return freePlot;
    }

    /*
     * (non-Javadoc)
     * @see com.bdb.weather.display.freeplot.FreePlot.SeriesCollectionFactory#createSeriesGroupControls(java.awt.event.ActionListener)
     */
    @Override
    public Map<String, SeriesGroupControl> createSeriesGroupControls(EventHandler<ActionEvent> listener) {
        Map<String, SeriesGroupControl> list = new TreeMap<>();

        SeriesGroupControl groupControl = new SeriesGroupControl(TEMPERATURE_COLLECTION_NAME,
                TemperatureRangeAxis.create(), listener);
        groupControl.addSeriesControl(new SeriesControl(OUTDOOR_TEMPERATURE_SERIES_NAME, listener));
        groupControl.addSeriesControl(new SeriesControl(INDOOR_TEMPERATURE_SERIES_NAME, listener));
        groupControl.addSeriesControl(new SeriesControl(DEW_POINT_SERIES_NAME, listener));
        groupControl.addSeriesControl(new SeriesControl(HEAT_INDEX_SERIES_NAME, listener));
        groupControl.addSeriesControl(new SeriesControl(WIND_CHILL_SERIES_NAME, listener));
        for (Sensor sensor : ws.getSensorManager().getExtraSensors(SensorType.THERMOMETER)) {
            groupControl.addSeriesControl(new SeriesControl(sensor.getName(), listener));
        }
        list.put(groupControl.getGroupName(), groupControl);

        groupControl = new SeriesGroupControl(HUMIDITY_COLLECTION_NAME, HumidityRangeAxis.create(), listener);
        groupControl.addSeriesControl(new SeriesControl(OUTDOOR_HUMIDITY_SERIES_NAME, listener));
        groupControl.addSeriesControl(new SeriesControl(INDOOR_HUMIDITY_SERIES_NAME, listener));
        list.put(groupControl.getGroupName(), groupControl);

        groupControl = new SeriesGroupControl(PRESSURE_COLLECTION_NAME, PressureRangeAxis.create(), listener);
        groupControl.addSeriesControl(new SeriesControl(BAROMETRIC_PRESSURE_SERIES_NAME, listener));
        list.put(groupControl.getGroupName(), groupControl);

        groupControl = new SeriesGroupControl(WIND_COLLECTION_NAME, WindSpeedRangeAxis.create(), listener);
        groupControl.addSeriesControl(new SeriesControl(SUSTAINED_WIND_SERIES_NAME, listener));
        groupControl.addSeriesControl(new SeriesControl(HIGH_WIND_SERIES_NAME, listener));
        groupControl.addSeriesControl(new SeriesControl(WIND_GUST_SERIES_NAME, listener));
        list.put(groupControl.getGroupName(), groupControl);

        groupControl = new SeriesGroupControl(RAIN_COLLECTION_NAME, RainRangeAxis.create(), listener);
        groupControl.addSeriesControl(new SeriesControl(RAIN_SERIES_NAME, listener));
        groupControl.addSeriesControl(new SeriesControl(HIGH_RAIN_RATE_SERIES_NAME, listener));
        list.put(groupControl.getGroupName(), groupControl);

        groupControl = new SeriesGroupControl(SOLAR_RADIATION_COLLECTION_NAME, SolarRadiationAxis.create(),
                listener);
        groupControl.addSeriesControl(new SeriesControl(SOLAR_RADIATION_SERIES_NAME, listener));
        list.put(groupControl.getGroupName(), groupControl);

        groupControl = new SeriesGroupControl(UV_INDEX_COLLECTION_NAME, UvIndexAxis.create(), listener);
        groupControl.addSeriesControl(new SeriesControl(UV_INDEX_SERIES_NAME, listener));
        list.put(groupControl.getGroupName(), groupControl);

        return list;
    }

    /*
     * (non-Javadoc)
     * @see com.bdb.weather.display.freeplot.FreePlotSeriesCollection.SeriesFactory#createSeriesGroup(java.lang.String, java.awt.Stroke)
     */
    @Override
    public List<FreePlotSeries<HistoricalRecord>> createSeriesGroup(String groupName, Stroke stroke) {
        List<FreePlotSeries<HistoricalRecord>> list = new ArrayList<>();

        Function<HistoricalRecord, TemporalAccessor> timeMethod = HistoricalRecord::getTime;
        switch (groupName) {
        case TEMPERATURE_COLLECTION_NAME:
            list = createTemperatureSeries(stroke, timeMethod);
            break;
        case HUMIDITY_COLLECTION_NAME:
            list = createHumiditySeries(stroke, timeMethod);
            break;
        case PRESSURE_COLLECTION_NAME:
            list = createPressureSeries(stroke, timeMethod);
            break;
        case WIND_COLLECTION_NAME:
            list = createWindSeries(stroke, timeMethod);
            break;
        case RAIN_COLLECTION_NAME:
            list = createRainSeries(stroke, timeMethod);
            break;
        case SOLAR_RADIATION_COLLECTION_NAME:
            list = createSolarRadiationSeries(stroke, timeMethod);
            break;
        case UV_INDEX_COLLECTION_NAME:
            list = createUvIndexSeries(stroke, timeMethod);
            break;
        }

        return list;
    }

    /*
     * (non-Javadoc)
     * @see com.bdb.weather.display.freeplot.FreePlot.SeriesCollectionFactory#createSeriesCollections(org.jfree.chart.plot.XYPlot, int, java.awt.Stroke)
     */
    @Override
    public List<FreePlotSeriesCollection> createSeriesCollections(XYPlot plot, int domainAxisIndex, Stroke stroke) {
        List<FreePlotSeriesCollection> list = new ArrayList<>();
        list.add(new FreePlotSeriesCollection(TEMPERATURE_COLLECTION_NAME, Temperature.getDefaultUnit(),
                (NUM_COLLECTIONS * domainAxisIndex) + 0, domainAxisIndex, plot, stroke, this));
        list.add(new FreePlotSeriesCollection(HUMIDITY_COLLECTION_NAME, Humidity.Unit.RELATIVE_HUMIDITY,
                (NUM_COLLECTIONS * domainAxisIndex) + 1, domainAxisIndex, plot, stroke, this));
        list.add(new FreePlotSeriesCollection(PRESSURE_COLLECTION_NAME, Pressure.getDefaultUnit(),
                (NUM_COLLECTIONS * domainAxisIndex) + 2, domainAxisIndex, plot, stroke, this));
        list.add(new FreePlotSeriesCollection(WIND_COLLECTION_NAME, Speed.getDefaultUnit(),
                (NUM_COLLECTIONS * domainAxisIndex) + 3, domainAxisIndex, plot, stroke, this));
        list.add(new FreePlotSeriesCollection(RAIN_COLLECTION_NAME, Depth.getDefaultUnit(),
                (NUM_COLLECTIONS * domainAxisIndex) + 4, domainAxisIndex, plot, stroke, this));
        list.add(new FreePlotSeriesCollection(SOLAR_RADIATION_COLLECTION_NAME, SolarRadiation.getDefaultUnit(),
                (NUM_COLLECTIONS * domainAxisIndex) + 5, domainAxisIndex, plot, stroke, this));
        list.add(new FreePlotSeriesCollection(UV_INDEX_COLLECTION_NAME, null,
                (NUM_COLLECTIONS * domainAxisIndex) + 6, domainAxisIndex, plot, stroke, this));

        return list;
    }

    /*
     * (non-Javadoc)
     * @see com.bdb.weather.display.freeplot.FreePlotSeriesCollection.SeriesFactory#updateRenderer(com.bdb.weather.display.freeplot.FreePlotSeries, org.jfree.chart.renderer.xy.DefaultXYItemRenderer)
     */
    @Override
    public void updateRenderer(FreePlotSeries series, DefaultXYItemRenderer renderer) {
        int index = series.getSeriesIndex();
        if (series.getName().equals(WIND_GUST_SERIES_NAME))
            WeatherSenseConstants.configureGustRenderer(renderer, index);
        else if (series.getName().equals(SUSTAINED_WIND_SERIES_NAME)) {
            renderer.setSeriesLinesVisible(index, true);
            renderer.setSeriesShapesVisible(index, false);
        }
    }

    // TODO Change the paints to use preferences 
    /**
     * Create the series for temperature values.
     * 
     * @param stroke The stroke that is used to draw the series
     * @param timeMethod The method that is used to "get" the date from the record
     */
    private List<FreePlotSeries<HistoricalRecord>> createTemperatureSeries(Stroke stroke,
            Function<HistoricalRecord, TemporalAccessor> timeMethod) {
        List<FreePlotSeries<HistoricalRecord>> list = new ArrayList<>();
        int n = 0;
        list.add(new FreePlotSeries<>(OUTDOOR_TEMPERATURE_SERIES_NAME, n++,
                StageUtilities.toAwtColor(ColorPreferences.getInstance().getOutdoorTempColorPref()), stroke,
                HistoricalRecord::getAvgOutdoorTemperature, timeMethod, INTERVAL_CLASS));
        list.add(new FreePlotSeries<>(INDOOR_TEMPERATURE_SERIES_NAME, n++,
                StageUtilities.toAwtColor(ColorPreferences.getInstance().getIndoorTempColorPref()), stroke,
                HistoricalRecord::getIndoorTemperature, timeMethod, INTERVAL_CLASS));
        list.add(new FreePlotSeries<>(DEW_POINT_SERIES_NAME, n++, Color.BLUE, stroke, HistoricalRecord::getDewPoint,
                timeMethod, INTERVAL_CLASS));
        list.add(new FreePlotSeries<>(HEAT_INDEX_SERIES_NAME, n++, Color.MAGENTA, stroke,
                HistoricalRecord::getHeatIndex, timeMethod, INTERVAL_CLASS));
        list.add(new FreePlotSeries<>(WIND_CHILL_SERIES_NAME, n++, Color.PINK, stroke,
                HistoricalRecord::getWindChill, timeMethod, INTERVAL_CLASS));
        for (Sensor sensor : ws.getSensorManager().getExtraSensors(SensorType.THERMOMETER)) {
            Object[] args = { sensor.getSensorId() };
            Class[] argTypes = { int.class };
            //list.add(new FreePlotSeries(sensor.getName(), n++, Color.BLUE.brighter(), stroke, HistoricalRecord.class.getMethod("getTemperatureForSensor", argTypes), args, timeMethod, INTERVAL_CLASS));
        }

        return list;
    }

    /**
     * Create the series for humidity values.
     * 
     * @param stroke The stroke that is used to draw the series
     * @param timeMethod The method that is used to "get" the date from the record
     */
    private List<FreePlotSeries<HistoricalRecord>> createHumiditySeries(Stroke stroke,
            Function<HistoricalRecord, TemporalAccessor> timeMethod) {
        List<FreePlotSeries<HistoricalRecord>> list = new ArrayList<>();
        int n = 0;
        list.add(new FreePlotSeries<>(OUTDOOR_HUMIDITY_SERIES_NAME, n++, Color.GRAY, stroke,
                HistoricalRecord::getOutdoorHumidity, timeMethod, INTERVAL_CLASS));
        list.add(new FreePlotSeries<>(INDOOR_HUMIDITY_SERIES_NAME, n++, Color.BLACK, stroke,
                HistoricalRecord::getIndoorHumidity, timeMethod, INTERVAL_CLASS));

        return list;
    }

    /**
     * Create the series for pressure values.
     * 
     * @param stroke The stroke that is used to draw the series
     * @param timeMethod The method that is used to "get" the date from the record
     */
    private List<FreePlotSeries<HistoricalRecord>> createPressureSeries(Stroke stroke,
            Function<HistoricalRecord, TemporalAccessor> timeMethod) {
        List<FreePlotSeries<HistoricalRecord>> list = new ArrayList<>();
        int n = 0;
        list.add(new FreePlotSeries<>(BAROMETRIC_PRESSURE_SERIES_NAME, n++, Color.ORANGE, stroke,
                HistoricalRecord::getBaroPressure, timeMethod, INTERVAL_CLASS));

        return list;
    }

    /**
     * Create the series for wind values.
     * 
     * @param stroke The stroke that is used to draw the series
     * @param timeMethod The method that is used to "get" the date from the record
     */
    private List<FreePlotSeries<HistoricalRecord>> createWindSeries(Stroke stroke,
            Function<HistoricalRecord, TemporalAccessor> timeMethod) {
        List<FreePlotSeries<HistoricalRecord>> list = new ArrayList<>();
        int n = 0;
        list.add(new FreePlotSeries<>(SUSTAINED_WIND_SERIES_NAME, n++, Color.CYAN, stroke,
                HistoricalRecord::getAvgWindSpeed, timeMethod, INTERVAL_CLASS));
        list.add(new FreePlotSeries<>(SUSTAINED_WIND_SERIES_NAME, n++, Color.ORANGE, stroke,
                HistoricalRecord::getHighWindSpeed, timeMethod, INTERVAL_CLASS));
        list.add(new FreePlotSeries<>(WIND_GUST_SERIES_NAME, n++, Color.yellow, stroke,
                HistoricalRecord::getWindGustSpeed, timeMethod, INTERVAL_CLASS));

        return list;
    }

    /**
     * Create the series for rain values.
     * 
     * @param stroke The stroke that is used to draw the series
     * @param timeMethod The method that is used to "get" the date from the record
     */
    private List<FreePlotSeries<HistoricalRecord>> createRainSeries(Stroke stroke,
            Function<HistoricalRecord, TemporalAccessor> timeMethod) {
        List<FreePlotSeries<HistoricalRecord>> list = new ArrayList<>();
        int n = 0;
        list.add(new FreePlotSeries<>(RAIN_SERIES_NAME, n++, Color.BLUE, stroke, HistoricalRecord::getRainfall,
                timeMethod, INTERVAL_CLASS));
        list.add(new FreePlotSeries<>(HIGH_RAIN_RATE_SERIES_NAME, n++, Color.CYAN, stroke,
                HistoricalRecord::getHighRainfallRate, timeMethod, INTERVAL_CLASS));

        return list;
    }

    /**
     * Create the series for pressure values.
     * 
     * @param stroke The stroke that is used to draw the series
     * @param timeMethod The method that is used to "get" the date from the record
     */
    private List<FreePlotSeries<HistoricalRecord>> createSolarRadiationSeries(Stroke stroke,
            Function<HistoricalRecord, TemporalAccessor> timeMethod) {
        List<FreePlotSeries<HistoricalRecord>> list = new ArrayList<>();
        int n = 0;
        list.add(new FreePlotSeries<>(SOLAR_RADIATION_SERIES_NAME, n++, Color.ORANGE, stroke,
                HistoricalRecord::getAvgSolarRadiation, timeMethod, INTERVAL_CLASS));

        return list;
    }

    /**
     * Create the series for pressure values.
     * 
     * @param stroke The stroke that is used to draw the series
     * @param timeMethod The method that is used to "get" the date from the record
     */
    private List<FreePlotSeries<HistoricalRecord>> createUvIndexSeries(Stroke stroke,
            Function<HistoricalRecord, TemporalAccessor> timeMethod) {
        List<FreePlotSeries<HistoricalRecord>> list = new ArrayList<>();
        int n = 0;
        //list.add(new FreePlotSeries<>(UV_INDEX_SERIES_NAME, n++, Color.ORANGE, stroke, HistoricalRecord::getAvgUvIndex, timeMethod, INTERVAL_CLASS));
        return list;
    }

    /*
     * (non-Javadoc)
     * @see com.bdb.weather.display.freeplot.FreePlot.SeriesCollectionFactory#retrieveData(java.lang.String, java.util.Calendar, java.util.Calendar)
     */
    @Override
    public List<?> retrieveData(LocalDateTime startDate, LocalDateTime endDate) throws SQLException {
        List<HistoricalRecord> list = table.queryRecordsForTimePeriod(startDate, endDate);
        return list;
    }
}