playground.dgrether.events.handlers.DgGeoFilteredLegHistogram.java Source code

Java tutorial

Introduction

Here is the source code for playground.dgrether.events.handlers.DgGeoFilteredLegHistogram.java

Source

/* *********************************************************************** *
 * project: org.matsim.*
 * DgLegHistogram
 *                                                                         *
 * *********************************************************************** *
 *                                                                         *
 * copyright       : (C) 2012 by the members listed in the COPYING,        *
 *                   LICENSE and WARRANTY file.                            *
 * email           : info at matsim dot org                                *
 *                                                                         *
 * *********************************************************************** *
 *                                                                         *
 *   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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *   See also COPYING, LICENSE and WARRANTY file                           *
 *                                                                         *
 * *********************************************************************** */
package playground.dgrether.events.handlers;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.util.HashMap;
import java.util.Map;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.matsim.api.core.v01.Id;
import org.matsim.api.core.v01.events.PersonArrivalEvent;
import org.matsim.api.core.v01.events.PersonStuckEvent;
import org.matsim.api.core.v01.events.Event;
import org.matsim.api.core.v01.events.LinkEnterEvent;
import org.matsim.api.core.v01.events.LinkLeaveEvent;
import org.matsim.api.core.v01.events.handler.PersonArrivalEventHandler;
import org.matsim.api.core.v01.events.handler.PersonStuckEventHandler;
import org.matsim.api.core.v01.events.handler.LinkEnterEventHandler;
import org.matsim.api.core.v01.events.handler.LinkLeaveEventHandler;
import org.matsim.api.core.v01.network.Network;
import org.matsim.core.utils.collections.Tuple;
import org.matsim.core.utils.misc.Time;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import playground.dgrether.events.GeospatialEventTools;

/**
 * @author dgrether
 *  based on implementation of mrieser in the org.matsim project
 *
 */
public class DgGeoFilteredLegHistogram implements LinkEnterEventHandler, LinkLeaveEventHandler,
        PersonArrivalEventHandler, PersonStuckEventHandler {

    private Map<Id, LinkEnterEvent> firstTimeSeenMap;
    private Map<Id, LinkLeaveEvent> lastTimeSeenMap;
    private GeospatialEventTools geospatialTools;
    private int iteration = 0;
    private final int binSizeSeconds;
    private final int nofBins;
    private ModeData allModesData = null;

    public DgGeoFilteredLegHistogram(Network network, CoordinateReferenceSystem networkCrs,
            final int binSizeSeconds, final int nofBins) {
        this.geospatialTools = new GeospatialEventTools(network, networkCrs);
        this.binSizeSeconds = binSizeSeconds;
        this.nofBins = nofBins;
        this.firstTimeSeenMap = new HashMap<Id, LinkEnterEvent>();
        this.lastTimeSeenMap = new HashMap<Id, LinkLeaveEvent>();
        reset(0);
    }

    public DgGeoFilteredLegHistogram(Network network, CoordinateReferenceSystem networkCrs,
            final int binSizeSeconds) {
        this(network, networkCrs, binSizeSeconds, 30 * 3600 / binSizeSeconds + 1);
    }

    @Override
    public void reset(int iteration) {
        this.iteration = iteration;
        this.allModesData = new ModeData(this.nofBins + 1);
        this.firstTimeSeenMap.clear();
        this.lastTimeSeenMap.clear();
    }

    @Override
    public void handleEvent(LinkLeaveEvent event) {
        if (this.geospatialTools.doNetworkAndFeaturesContainLink(event.getLinkId())) {
            this.lastTimeSeenMap.put(event.getPersonId(), event);
        }
    }

    @Override
    public void handleEvent(LinkEnterEvent event) {
        if (this.geospatialTools.doNetworkAndFeaturesContainLink(event.getLinkId())) {
            if (!this.firstTimeSeenMap.containsKey(event.getPersonId())) {
                this.firstTimeSeenMap.put(event.getPersonId(), event);
            }
        }
    }

    private void handleArrivalOrStuck(Event event, Id personId) {
        LinkEnterEvent firstEvent = this.firstTimeSeenMap.remove(personId);
        LinkLeaveEvent lastEvent = this.lastTimeSeenMap.remove(personId);
        if (firstEvent != null && lastEvent != null) {
            int index = getBinIndex(firstEvent.getTime());
            this.allModesData.countsDep[index]++;
            index = getBinIndex(lastEvent.getTime());
            this.allModesData.countsArr[index]++;
        }
    }

    @Override
    public void handleEvent(PersonStuckEvent event) {
        this.handleArrivalOrStuck(event, event.getPersonId());
    }

    @Override
    public void handleEvent(PersonArrivalEvent event) {
        this.handleArrivalOrStuck(event, event.getPersonId());
    }

    public void addCrsFeatureTuple(Tuple<CoordinateReferenceSystem, SimpleFeature> cottbusFeatureTuple) {
        this.geospatialTools.addCrsFeatureTuple(cottbusFeatureTuple);
    }

    /**
     * Writes the gathered data tab-separated into a text file.
     *
     * @param filename The name of a file where to write the gathered data.
     */
    public void write(final String filename) {
        PrintStream stream;
        try {
            stream = new PrintStream(new File(filename));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return;
        }
        write(stream);
        stream.close();
    }

    /**
     * Writes the gathered data tab-separated into a text stream.
     *
     * @param stream The data stream where to write the gathered data.
     */
    public void write(final PrintStream stream) {
        stream.print("time\ttime\tdepartures_all\tarrivals_all\tstuck_all\ten-route_all");
        stream.print("\n");
        int allEnRoute = 0;
        for (int i = 0; i < this.allModesData.countsDep.length; i++) {
            // data about all modes
            allEnRoute = allEnRoute + this.allModesData.countsDep[i] - this.allModesData.countsArr[i]
                    - this.allModesData.countsStuck[i];
            stream.print(Time.writeTime(i * this.binSizeSeconds) + "\t" + i * this.binSizeSeconds);
            stream.print("\t" + this.allModesData.countsDep[i] + "\t" + this.allModesData.countsArr[i] + "\t"
                    + this.allModesData.countsStuck[i] + "\t" + allEnRoute);
            // new line
            stream.print("\n");
        }
    }

    /**
     * @return a graphic showing the number of departures, arrivals and vehicles
     * en route of all legs/trips
     */
    public JFreeChart getGraphic() {
        return getGraphic(this.allModesData, "all");
    }

    private JFreeChart getGraphic(final ModeData modeData, final String modeName) {
        final XYSeriesCollection xyData = new XYSeriesCollection();
        final XYSeries departuresSerie = new XYSeries("departures", false, true);
        final XYSeries arrivalsSerie = new XYSeries("arrivals", false, true);
        final XYSeries onRouteSerie = new XYSeries("en route", false, true);
        int onRoute = 0;
        for (int i = 0; i < modeData.countsDep.length; i++) {
            onRoute = onRoute + modeData.countsDep[i] - modeData.countsArr[i] - modeData.countsStuck[i];
            double hour = i * this.binSizeSeconds / 60.0 / 60.0;
            departuresSerie.add(hour, modeData.countsDep[i]);
            arrivalsSerie.add(hour, modeData.countsArr[i]);
            onRouteSerie.add(hour, onRoute);
        }

        xyData.addSeries(departuresSerie);
        xyData.addSeries(arrivalsSerie);
        xyData.addSeries(onRouteSerie);

        final JFreeChart chart = ChartFactory.createXYStepChart(
                "Leg Histogram, " + modeName + ", it." + this.iteration, "time", "# vehicles", xyData,
                PlotOrientation.VERTICAL, true, // legend
                false, // tooltips
                false // urls
        );

        XYPlot plot = chart.getXYPlot();
        plot.getRenderer().setSeriesStroke(0, new BasicStroke(2.0f));
        plot.getRenderer().setSeriesStroke(1, new BasicStroke(2.0f));
        plot.getRenderer().setSeriesStroke(2, new BasicStroke(2.0f));
        plot.setBackgroundPaint(Color.white);
        plot.setRangeGridlinePaint(Color.gray);
        plot.setDomainGridlinePaint(Color.gray);

        final CategoryAxis axis1 = new CategoryAxis("hour");
        axis1.setTickLabelFont(new Font("SansSerif", Font.PLAIN, 7));
        plot.setDomainAxis(new NumberAxis("time"));
        return chart;
    }

    /**
     * Writes a graphic showing the number of departures, arrivals and vehicles
     * en route of all legs/trips to the specified file.
     *
     * @param filename
     *
     * @see #getGraphic()
     */
    public void writeGraphic(final String filename) {
        try {
            ChartUtilities.saveChartAsPNG(new File(filename), getGraphic(), 1024, 768);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /* private methods */

    private int getBinIndex(final double time) {
        int bin = (int) (time / this.binSizeSeconds);
        if (bin >= this.nofBins) {
            return this.nofBins;
        }
        return bin;
    }

    private static class ModeData {
        public final int[] countsDep;
        public final int[] countsArr;
        public final int[] countsStuck;

        public ModeData(final int nofBins) {
            this.countsDep = new int[nofBins];
            this.countsArr = new int[nofBins];
            this.countsStuck = new int[nofBins];
        }
    }

}