├── data ├── data_years.txt ├── sample_merged_1.kdtrip └── extra_fields.txt ├── doc ├── data_import.pdf ├── figs │ ├── process.png │ └── taxivis.png └── MAP_RESTORATION_PLAN.md ├── .gitignore ├── src ├── TaxiVis │ ├── Resources │ │ ├── icons │ │ │ ├── map.png │ │ │ ├── config.png │ │ │ ├── export.png │ │ │ ├── link.png │ │ │ ├── merge.png │ │ │ ├── pause.png │ │ │ ├── pickup.png │ │ │ ├── play.png │ │ │ ├── reset.png │ │ │ ├── time.png │ │ │ ├── dropoff.png │ │ │ ├── explore.png │ │ │ ├── time_on.png │ │ │ ├── unmerge.png │ │ │ ├── animation.png │ │ │ ├── config_on.png │ │ │ ├── sync.color.png │ │ │ ├── sync.gray.png │ │ │ └── pickup_dropoff.png │ │ ├── qualitative.colors │ │ └── shaders │ │ │ ├── paths.120.vert │ │ │ ├── paths.120.frag │ │ │ ├── location.120.vert │ │ │ ├── geo2screen.120.vert │ │ │ └── paths.120.geom │ ├── util │ │ ├── divergent.h │ │ ├── grayscale.h │ │ ├── locsscale.h │ │ ├── rainbowscale.h │ │ ├── sequentialred.h │ │ ├── bluetocyanscale.h │ │ ├── lineargrayscale.h │ │ ├── bluetoyellowscale.h │ │ ├── greentowhitescale.h │ │ ├── heatedobjectscale.h │ │ ├── pseudorainbowscale.h │ │ ├── yellowtobrownscale.h │ │ ├── scalar.cpp │ │ ├── sequentialred.cpp │ │ ├── greentowhitescale.cpp │ │ ├── pseudorainbowscale.cpp │ │ ├── yellowtobrownscale.cpp │ │ ├── scalar.h │ │ ├── colorscale.h │ │ ├── colorbar.h │ │ └── colorscale.cpp │ ├── main.cpp │ ├── Group.h │ ├── querymanager.h │ ├── layers │ │ ├── TripLocationLOD.hpp │ │ ├── TripLocation.hpp │ │ ├── HeatMap.hpp │ │ ├── TripAnimationConfig.ui │ │ ├── TripAnimation.hpp │ │ ├── Triangulator.cpp │ │ ├── TripLocation.cpp │ │ ├── TripAnimationToolBar.ui │ │ └── GridMap.hpp │ ├── neighborhood.h │ ├── neighborhood.cpp │ ├── mainwindow.h │ ├── neighborhoodgraph.h │ ├── neighborhoodset.h │ ├── extendedplotwidget.h │ ├── TemporalSeriesDialog.hpp │ ├── GroupRepository.h │ ├── RenderingLayer.cpp │ ├── TimeExplorationDialog.hpp │ ├── HistogramDialog.hpp │ ├── QMapWidget.hpp │ ├── timeselectionwidget.h │ ├── Group.cpp │ ├── mainwindow.cpp │ ├── Selection.h │ ├── global.h │ ├── resources.qrc │ ├── viewwidget.h │ ├── timeanalysiswidget.h │ ├── neighborhoodgraph.cpp │ ├── scatterplotwidget.h │ ├── QMapWidget.cpp │ ├── timewidget.ui │ ├── extendedhistogram.h │ ├── timewidget.h │ ├── mainwindow.ui │ ├── coordinator.h │ ├── neighborhoodset.cpp │ ├── QMapView.hpp │ ├── GroupRepository.cpp │ ├── histogramwidget.h │ ├── Selection.cpp │ ├── UsefulGeometryFunctions.h │ ├── QMapTileWidget.hpp │ ├── TimeExplorationDialog.cpp │ ├── global.cpp │ ├── RenderingLayer.hpp │ ├── HistogramDialog.ui │ ├── TimeExplorationDialog.ui │ ├── TaxiVis.pro │ ├── TemporalSeriesDialog.ui │ ├── extendedplotwidget.cpp │ ├── SelectionGraph.h │ ├── CMakeLists.txt │ ├── coordinator.cpp │ ├── timeselectionwidget.cpp │ ├── HistogramDialog.cpp │ ├── histogramwidget.ui │ └── temporalseriesplotwidget.h └── preprocess │ ├── testQuery.cpp │ ├── CMakeLists.txt │ ├── merge.jl │ ├── merge.py │ ├── unif96_to_bin.cpp │ ├── newFormatCsv2Binary.cpp │ ├── csv2Binary.cpp │ ├── radix.h │ └── csv2Binary.jl ├── CMakeLists.txt ├── LICENSE └── process_taxi_data.sh /data/data_years.txt: -------------------------------------------------------------------------------- 1 | 2011 2 | 2012 3 | 2013 4 | 2014 5 | 2015 6 | -------------------------------------------------------------------------------- /doc/data_import.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/doc/data_import.pdf -------------------------------------------------------------------------------- /doc/figs/process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/doc/figs/process.png -------------------------------------------------------------------------------- /doc/figs/taxivis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/doc/figs/taxivis.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | 3 | # Large data files 4 | data/*.csv 5 | data/*.trip 6 | data/*.kdtrip 7 | -------------------------------------------------------------------------------- /data/sample_merged_1.kdtrip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/data/sample_merged_1.kdtrip -------------------------------------------------------------------------------- /src/TaxiVis/Resources/icons/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/src/TaxiVis/Resources/icons/map.png -------------------------------------------------------------------------------- /src/TaxiVis/Resources/icons/config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/src/TaxiVis/Resources/icons/config.png -------------------------------------------------------------------------------- /src/TaxiVis/Resources/icons/export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/src/TaxiVis/Resources/icons/export.png -------------------------------------------------------------------------------- /src/TaxiVis/Resources/icons/link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/src/TaxiVis/Resources/icons/link.png -------------------------------------------------------------------------------- /src/TaxiVis/Resources/icons/merge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/src/TaxiVis/Resources/icons/merge.png -------------------------------------------------------------------------------- /src/TaxiVis/Resources/icons/pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/src/TaxiVis/Resources/icons/pause.png -------------------------------------------------------------------------------- /src/TaxiVis/Resources/icons/pickup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/src/TaxiVis/Resources/icons/pickup.png -------------------------------------------------------------------------------- /src/TaxiVis/Resources/icons/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/src/TaxiVis/Resources/icons/play.png -------------------------------------------------------------------------------- /src/TaxiVis/Resources/icons/reset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/src/TaxiVis/Resources/icons/reset.png -------------------------------------------------------------------------------- /src/TaxiVis/Resources/icons/time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/src/TaxiVis/Resources/icons/time.png -------------------------------------------------------------------------------- /src/TaxiVis/Resources/icons/dropoff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/src/TaxiVis/Resources/icons/dropoff.png -------------------------------------------------------------------------------- /src/TaxiVis/Resources/icons/explore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/src/TaxiVis/Resources/icons/explore.png -------------------------------------------------------------------------------- /src/TaxiVis/Resources/icons/time_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/src/TaxiVis/Resources/icons/time_on.png -------------------------------------------------------------------------------- /src/TaxiVis/Resources/icons/unmerge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/src/TaxiVis/Resources/icons/unmerge.png -------------------------------------------------------------------------------- /src/TaxiVis/Resources/icons/animation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/src/TaxiVis/Resources/icons/animation.png -------------------------------------------------------------------------------- /src/TaxiVis/Resources/icons/config_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/src/TaxiVis/Resources/icons/config_on.png -------------------------------------------------------------------------------- /src/TaxiVis/Resources/icons/sync.color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/src/TaxiVis/Resources/icons/sync.color.png -------------------------------------------------------------------------------- /src/TaxiVis/Resources/icons/sync.gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/src/TaxiVis/Resources/icons/sync.gray.png -------------------------------------------------------------------------------- /src/TaxiVis/Resources/icons/pickup_dropoff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VIDA-NYU/TaxiVis/HEAD/src/TaxiVis/Resources/icons/pickup_dropoff.png -------------------------------------------------------------------------------- /data/extra_fields.txt: -------------------------------------------------------------------------------- 1 | field1,Screen Name1,Axis Label1,1 2 | field2,Screen Name2,Axis Label2,1 3 | field3,Screen Name3,Axis Label3,0 4 | field4,Screen Name4,Axis Label4,0 5 | -------------------------------------------------------------------------------- /src/TaxiVis/Resources/qualitative.colors: -------------------------------------------------------------------------------- 1 | 255 255 255 2 | 31 119 180 3 | 255 127 14 4 | 44 160 44 5 | 214 39 40 6 | 148 103 189 7 | 140 86 75 8 | 227 119 194 9 | 127 127 127 10 | 188 189 34 11 | 23 190 207 -------------------------------------------------------------------------------- /src/TaxiVis/util/divergent.h: -------------------------------------------------------------------------------- 1 | #ifndef DIVERGENT_H 2 | #define DIVERGENT_H 3 | 4 | #include "util/colorscale.h" 5 | 6 | class Divergent: public ColorScale { 7 | public: 8 | Divergent(); 9 | }; 10 | 11 | #endif // GRAYSCALE_H 12 | -------------------------------------------------------------------------------- /src/TaxiVis/util/grayscale.h: -------------------------------------------------------------------------------- 1 | #ifndef GRAYSCALE_H 2 | #define GRAYSCALE_H 3 | 4 | #include "util/colorscale.h" 5 | 6 | class GrayScale: public ColorScale { 7 | public: 8 | GrayScale(); 9 | }; 10 | 11 | #endif // GRAYSCALE_H 12 | -------------------------------------------------------------------------------- /src/TaxiVis/util/locsscale.h: -------------------------------------------------------------------------------- 1 | #ifndef LOCSSCALE_H 2 | #define LOCSSCALE_H 3 | 4 | #include "util/colorscale.h" 5 | 6 | class LocsScale: public ColorScale { 7 | public: 8 | LocsScale(); 9 | }; 10 | 11 | #endif // LOCSSCALE_H 12 | -------------------------------------------------------------------------------- /src/TaxiVis/util/rainbowscale.h: -------------------------------------------------------------------------------- 1 | #ifndef RAINBOWSCALE_H 2 | #define RAINBOWSCALE_H 3 | 4 | #include "util/colorscale.h" 5 | 6 | class RainbowScale: public ColorScale { 7 | public: 8 | RainbowScale(); 9 | }; 10 | 11 | #endif // RAINBOWSCALE_H 12 | -------------------------------------------------------------------------------- /src/TaxiVis/util/sequentialred.h: -------------------------------------------------------------------------------- 1 | #ifndef SEQUENTIALRED_H 2 | #define SEQUENTIALRED_H 3 | 4 | #include "util/colorscale.h" 5 | 6 | class SequentialRed:public ColorScale 7 | { 8 | public: 9 | SequentialRed(); 10 | }; 11 | 12 | #endif // SEQUENTIALRED_H 13 | -------------------------------------------------------------------------------- /src/TaxiVis/util/bluetocyanscale.h: -------------------------------------------------------------------------------- 1 | #ifndef BLUETOCYANSCALE_H 2 | #define BLUETOCYANSCALE_H 3 | 4 | #include "util/colorscale.h" 5 | 6 | class BlueToCyanScale: public ColorScale { 7 | public: 8 | BlueToCyanScale(); 9 | }; 10 | 11 | #endif // BLUETOCYANSCALE_H 12 | -------------------------------------------------------------------------------- /src/TaxiVis/util/lineargrayscale.h: -------------------------------------------------------------------------------- 1 | #ifndef LINEARGRAYSCALE_H 2 | #define LINEARGRAYSCALE_H 3 | 4 | #include "util/colorscale.h" 5 | 6 | class LinearGrayScale: public ColorScale { 7 | public: 8 | LinearGrayScale(); 9 | }; 10 | 11 | #endif // LINEARGRAYSCALE_H 12 | -------------------------------------------------------------------------------- /src/TaxiVis/util/bluetoyellowscale.h: -------------------------------------------------------------------------------- 1 | #ifndef BLUETOYELLOWSCALE_H 2 | #define BLUETOYELLOWSCALE_H 3 | 4 | #include "util/colorscale.h" 5 | 6 | class BlueToYellowScale: public ColorScale { 7 | public: 8 | BlueToYellowScale(); 9 | }; 10 | 11 | #endif // BLUETOYELLOWSCALE_H 12 | -------------------------------------------------------------------------------- /src/TaxiVis/util/greentowhitescale.h: -------------------------------------------------------------------------------- 1 | #ifndef GREENTOWHITESCALE_H 2 | #define GREENTOWHITESCALE_H 3 | 4 | #include "util/colorscale.h" 5 | 6 | class GreenToWhiteScale: public ColorScale { 7 | public: 8 | GreenToWhiteScale(); 9 | }; 10 | 11 | #endif // GREENTOWHITESCALE_H 12 | -------------------------------------------------------------------------------- /src/TaxiVis/util/heatedobjectscale.h: -------------------------------------------------------------------------------- 1 | #ifndef HEATEDOBJECTSCALE_H 2 | #define HEATEDOBJECTSCALE_H 3 | 4 | #include "util/colorscale.h" 5 | 6 | class HeatedObjectScale: public ColorScale { 7 | public: 8 | HeatedObjectScale(); 9 | }; 10 | 11 | #endif // HEATEDOBJECTSCALE_H 12 | -------------------------------------------------------------------------------- /src/TaxiVis/util/pseudorainbowscale.h: -------------------------------------------------------------------------------- 1 | #ifndef PSEUDORAINBOWSCALE_H 2 | #define PSEUDORAINBOWSCALE_H 3 | 4 | #include "util/colorscale.h" 5 | 6 | class PseudoRainbowScale: public ColorScale { 7 | public: 8 | PseudoRainbowScale(); 9 | }; 10 | 11 | #endif // PSEUDORAINBOWSCALE_H 12 | -------------------------------------------------------------------------------- /src/TaxiVis/util/yellowtobrownscale.h: -------------------------------------------------------------------------------- 1 | #ifndef YELLOWTOBROWNSCALE_H 2 | #define YELLOWTOBROWNSCALE_H 3 | 4 | #include "util/colorscale.h" 5 | 6 | class YellowToBrownScale: public ColorScale { 7 | public: 8 | YellowToBrownScale(); 9 | }; 10 | 11 | #endif // YELLOWTOBROWNSCALE_H 12 | -------------------------------------------------------------------------------- /src/TaxiVis/util/scalar.cpp: -------------------------------------------------------------------------------- 1 | #include "scalar.h" 2 | 3 | Scalar::Scalar( std::string name ): 4 | _min( 0.f ), _max( 0.f ), _name( name ), _index( -1 ) {} 5 | 6 | void Scalar::store( float value ) { 7 | if ( value > _max ) _max = value; 8 | if ( value < _min ) _min = value; 9 | } 10 | -------------------------------------------------------------------------------- /src/TaxiVis/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "global.h" 3 | #include "mainwindow.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | QApplication a(argc, argv); 8 | Global::getInstance(); //loads data 9 | MainWindow w; 10 | w.resize(1280, 800); 11 | w.show(); 12 | return a.exec(); 13 | } 14 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(TaxiVis) 3 | 4 | # Set C++ standard 5 | set(CMAKE_CXX_STANDARD 11) 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 | 8 | # Set build type 9 | set(CMAKE_BUILD_TYPE Debug CACHE STRING "Build type") 10 | 11 | # Add subdirectories 12 | add_subdirectory(src/preprocess) 13 | add_subdirectory(src/TaxiVis) 14 | -------------------------------------------------------------------------------- /src/TaxiVis/Resources/shaders/paths.120.vert: -------------------------------------------------------------------------------- 1 | #version 120 2 | #extension GL_EXT_gpu_shader4 : enable 3 | 4 | uniform int nVert; 5 | uniform int zoom; 6 | uniform vec2 center; 7 | uniform vec2 scale; 8 | 9 | attribute vec4 pos; 10 | 11 | void main(void) 12 | { 13 | gl_Position = (gl_VertexID1 || tex.x<0) discard; 9 | float alpha = 1-sqrt(tex.y*tex.y+tex.z*tex.z); 10 | vec4 srcColor = vec4(0.1, 0.3, 0.5, alpha); 11 | vec4 dstColor = vec4(1.0, 0.2, 0.1, alpha); 12 | gl_FragColor = mix(srcColor, dstColor, progress); 13 | } 14 | -------------------------------------------------------------------------------- /src/TaxiVis/Group.h: -------------------------------------------------------------------------------- 1 | #ifndef GROUP_H 2 | #define GROUP_H 3 | 4 | #include 5 | 6 | class Group 7 | { 8 | private: 9 | std::string name; 10 | QColor color; 11 | public: 12 | Group(); 13 | Group(QColor color); 14 | bool equals(const Group& g) const; 15 | const QColor &getColor() const; 16 | bool operator==(const Group&) const; 17 | bool operator <(const Group& b) const; 18 | }; 19 | 20 | #endif // GROUP_H 21 | -------------------------------------------------------------------------------- /src/TaxiVis/querymanager.h: -------------------------------------------------------------------------------- 1 | #ifndef QUERYMANGET_H 2 | #define QUERYMANGET_H 3 | 4 | #include "KdTrip.hpp" 5 | #include "SelectionGraph.h" 6 | #include 7 | 8 | class QueryManager 9 | { 10 | private: 11 | KdTrip* kdtrip; 12 | public: 13 | QueryManager(); 14 | ~QueryManager(); 15 | void queryData(SelectionGraph* queryGraph, QDateTime startTime, QDateTime endTime, KdTrip::TripSet &resultSet); 16 | }; 17 | 18 | #endif // QUERYMANGET_H 19 | -------------------------------------------------------------------------------- /src/TaxiVis/layers/TripLocationLOD.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TRIP_LOCATION_LOD_HPP 2 | #define TRIP_LOCATION_LOD_HPP 3 | #include "TripLocation.hpp" 4 | 5 | class GeographicalViewWidget; 6 | 7 | class TripLocationLOD : public TripLocation 8 | { 9 | Q_OBJECT 10 | public: 11 | TripLocationLOD(GeographicalViewWidget *mw); 12 | 13 | bool lodEnabled(); 14 | void setLodEnabled(bool b); 15 | 16 | protected: 17 | void buildLocations(); 18 | void renderGL(); 19 | 20 | bool lod; 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/TaxiVis/neighborhood.h: -------------------------------------------------------------------------------- 1 | #ifndef NEIGHBORHOOD_H 2 | #define NEIGHBORHOOD_H 3 | 4 | #include 5 | #include 6 | 7 | class Neighborhood 8 | { 9 | private: 10 | std::string name; 11 | 12 | public: 13 | Neighborhood(); 14 | Neighborhood(std::string name, const QVector& g); 15 | 16 | std::string getName(); 17 | QRectF getBBox(); 18 | bool contains(const QPointF &p); 19 | 20 | // 21 | QPolygonF geometry; 22 | }; 23 | 24 | #endif // NEIGHBORHOOD_H 25 | -------------------------------------------------------------------------------- /src/TaxiVis/util/sequentialred.cpp: -------------------------------------------------------------------------------- 1 | #include "sequentialred.h" 2 | 3 | SequentialRed::SequentialRed() 4 | { 5 | _colors.resize(9); 6 | _colors[ 0] = QColor(255, 245, 240); 7 | _colors[ 1] = QColor(254, 224, 210); 8 | _colors[ 2] = QColor(252, 187, 161); 9 | _colors[ 3] = QColor(252, 146, 114); 10 | _colors[ 4] = QColor(251, 106, 74); 11 | _colors[ 5] = QColor(239, 59, 44); 12 | _colors[ 6] = QColor(203, 24, 29); 13 | _colors[ 7] = QColor(165, 15, 21); 14 | _colors[ 8] = QColor(103, 0, 13); 15 | } 16 | -------------------------------------------------------------------------------- /src/TaxiVis/util/greentowhitescale.cpp: -------------------------------------------------------------------------------- 1 | #include "greentowhitescale.h" 2 | 3 | GreenToWhiteScale::GreenToWhiteScale():ColorScale() { 4 | _colors.resize(256); 5 | 6 | int mid = (int) (_colors.size() * 0.65f); 7 | 8 | for (int i = 0; i < mid; i++) { 9 | int value = (int) (((float) i / (float) mid) * 255); 10 | _colors[i] = QColor(0, value, 0); 11 | } 12 | 13 | for (unsigned i = mid; i < _colors.size(); i++) { 14 | int value = (int) (((float) (i - mid) / (float) (_colors.size() - 1 - mid)) * 255); 15 | _colors[i] = QColor(value, 255, value); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/TaxiVis/neighborhood.cpp: -------------------------------------------------------------------------------- 1 | #include "neighborhood.h" 2 | 3 | Neighborhood::Neighborhood(){ 4 | 5 | } 6 | 7 | Neighborhood::Neighborhood(std::string name, const QVector& g): 8 | name(name){ 9 | geometry = QPolygonF(g); 10 | } 11 | 12 | std::string Neighborhood::getName(){ 13 | return name; 14 | } 15 | 16 | QRectF Neighborhood::getBBox(){ 17 | return geometry.boundingRect(); 18 | } 19 | 20 | bool Neighborhood::contains(const QPointF &p){ 21 | QRectF bbox = getBBox(); 22 | if(!bbox.contains(p)) 23 | return false; 24 | 25 | return geometry.contains(p); 26 | } 27 | -------------------------------------------------------------------------------- /src/TaxiVis/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include "KdTrip.hpp" 6 | #include "SelectionGraph.h" 7 | 8 | namespace Ui { 9 | class MainWindow; 10 | } 11 | 12 | class MainWindow : public QMainWindow{ 13 | Q_OBJECT 14 | 15 | public: 16 | explicit MainWindow(QWidget *parent = 0); 17 | ~MainWindow(); 18 | 19 | private: 20 | Ui::MainWindow *ui; 21 | 22 | //signals: 23 | // void updateSelectedTrips(); 24 | 25 | public slots: 26 | void selectionChanged(); 27 | void addNewMap(); 28 | }; 29 | 30 | #endif // MAINWINDOW_H 31 | -------------------------------------------------------------------------------- /src/TaxiVis/neighborhoodgraph.h: -------------------------------------------------------------------------------- 1 | #ifndef NEIGHBORHOODGRAPH_H 2 | #define NEIGHBORHOODGRAPH_H 3 | 4 | #include 5 | 6 | class NeighborhoodGraph 7 | { 8 | public: 9 | std::vector edges; 10 | int numberOfNodes; 11 | 12 | public: 13 | NeighborhoodGraph(int numberOfNodes); 14 | NeighborhoodGraph(const std::vector &e, int numberOfNodes); 15 | void getBoundWeights(float &minWeight, float &maxWeight); 16 | float getEdge(int originIndex, int destinationIndex); 17 | void setEdges(float); 18 | void setEdges(const std::vector &e); 19 | }; 20 | 21 | #endif // NEIGHBORHOODGRAPH_H 22 | -------------------------------------------------------------------------------- /src/TaxiVis/Resources/shaders/location.120.vert: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | uniform float zoom; 4 | uniform vec2 center; 5 | uniform vec2 size; 6 | 7 | #define M_PI 3.14159265358979323846 8 | #define lat2worldY(lat) (log(tan(M_PI/4+lat*M_PI/360))) 9 | #define lat2y(lat) ((M_PI-lat2worldY(lat))/M_PI*128) 10 | #define lon2x(lon) ((lon+180)/360.0*256) 11 | 12 | void main(void) 13 | { 14 | float unit = exp2(zoom); 15 | vec4 screenPos = vec4((lon2x(gl_Vertex.y)-lon2x(center.y))*unit+size.x*0.5, 16 | (lat2y(gl_Vertex.x)-lat2y(center.x))*unit+size.y*0.5, 17 | 0.0, 1.0); 18 | gl_Position = gl_ModelViewProjectionMatrix*screenPos; 19 | gl_FrontColor = gl_Color; 20 | } 21 | -------------------------------------------------------------------------------- /src/TaxiVis/Resources/shaders/geo2screen.120.vert: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | uniform float zoom; 4 | uniform vec2 center; 5 | uniform vec2 size; 6 | 7 | #define M_PI 3.14159265358979323846 8 | #define lat2worldY(lat) (log(tan(M_PI/4+lat*M_PI/360))) 9 | #define lat2y(lat) ((M_PI-lat2worldY(lat))/M_PI*128) 10 | #define lon2x(lon) ((lon+180)/360.0*256) 11 | 12 | void main(void) 13 | { 14 | float unit = exp2(zoom); 15 | vec4 screenPos = vec4((lon2x(gl_Vertex.y)-lon2x(center.y))*unit+size.x*0.5, 16 | (lat2y(gl_Vertex.x)-lat2y(center.x))*unit+size.y*0.5, 17 | 0.0, 1.0); 18 | gl_Position = gl_ModelViewProjectionMatrix*screenPos; 19 | gl_FrontColor = gl_Color; 20 | } 21 | -------------------------------------------------------------------------------- /src/TaxiVis/neighborhoodset.h: -------------------------------------------------------------------------------- 1 | #ifndef NEIGHBORHOODSET_H 2 | #define NEIGHBORHOODSET_H 3 | 4 | #include 5 | #include "neighborhood.h" 6 | 7 | class NeighborhoodSet 8 | { 9 | private: 10 | std::map mapNamesToNeigh; 11 | public: 12 | NeighborhoodSet(); 13 | 14 | void loadGeometry(); 15 | Neighborhood* getByName(std::string name); 16 | Neighborhood* getNeighThatContains(const QPointF& geoLocation); 17 | int getNumberOfNeighborhoods(); 18 | 19 | void getIterators(std::map::iterator& begin, 20 | std::map::iterator& end); 21 | }; 22 | 23 | #endif // NEIGHBORHOODSET_H 24 | -------------------------------------------------------------------------------- /src/TaxiVis/util/pseudorainbowscale.cpp: -------------------------------------------------------------------------------- 1 | #include "pseudorainbowscale.h" 2 | #include 3 | 4 | PseudoRainbowScale::PseudoRainbowScale():ColorScale() { 5 | _colors.resize(256); 6 | 7 | float dx = 0.8f; 8 | 9 | for (unsigned i = 0; i < _colors.size(); i++) { 10 | float aux = (float) i / (_colors.size() - 1); 11 | float scaled = (6 - 2 * dx) * aux + dx; 12 | 13 | float r = std::max(0.f, (3 - std::abs(scaled - 4.f) - std::abs(scaled - 5.f)) / 2.f); 14 | float g = std::max(0.f, (4 - std::abs(scaled - 2.f) - std::abs(scaled - 4.f)) / 2.f); 15 | float b = std::max(0.f, (3 - std::abs(scaled - 1.f) - std::abs(scaled - 2.f)) / 2.f); 16 | 17 | _colors[i] = QColor(r*255, g*255, b*255); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/TaxiVis/util/yellowtobrownscale.cpp: -------------------------------------------------------------------------------- 1 | #include "yellowtobrownscale.h" 2 | 3 | #include 4 | 5 | QColor interpolate(const QColor &a, const QColor &b, float alpha) { 6 | int blue = std::min((1.f - alpha) * a.blue() + alpha * b.blue(), 255.f); 7 | int green = std::min((1.f - alpha) * a.green() + alpha * b.green(), 255.f); 8 | int red = std::min((1.f - alpha) * a.red() + alpha * b.red(), 255.f); 9 | return QColor(red, green, blue); 10 | } 11 | 12 | YellowToBrownScale::YellowToBrownScale() { 13 | _colors.resize(256); 14 | 15 | QColor yellow = Qt::yellow; 16 | QColor brown(139 ,69, 19); 17 | 18 | for (unsigned i=0; i<256; ++i) { 19 | _colors[i] = interpolate(yellow, brown, i/256.f); 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/TaxiVis/extendedplotwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef EXTENDEDPLOTWIDGET_H 2 | #define EXTENDEDPLOTWIDGET_H 3 | 4 | #include "qcustomplot.h" 5 | 6 | class ExtendedPlotWidget : public QCustomPlot 7 | { 8 | Q_OBJECT 9 | public: 10 | enum State {IDLE,SELECTION}; 11 | public: 12 | explicit ExtendedPlotWidget(QWidget *parent = 0); 13 | private: 14 | State currentState; 15 | QPointF lastPoint; 16 | QPointF currentPoint; 17 | QPointF mousePosition; 18 | bool buttonPressed; 19 | signals: 20 | void timeIntervalChanged(QDateTime,QDateTime); 21 | public slots: 22 | protected: 23 | void paintEvent(QPaintEvent *event); 24 | void mousePressEvent(QMouseEvent *event); 25 | void mouseMoveEvent(QMouseEvent *event); 26 | void mouseReleaseEvent(QMouseEvent *event); 27 | void leaveEvent(QEvent *); 28 | 29 | }; 30 | 31 | #endif // EXTENDEDPLOTWIDGET_H 32 | -------------------------------------------------------------------------------- /src/TaxiVis/TemporalSeriesDialog.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TEMPORAL_SERIES_DIALOG_H 2 | #define TEMPORAL_SERIES_DIALOG_H 3 | 4 | #include 5 | #include "extendedplotwidget.h" 6 | 7 | namespace Ui { 8 | class TemporalSeriesDialog; 9 | } 10 | class ExtendedPlotWidget; 11 | class GeographicalViewWidget; 12 | 13 | class TemporalSeriesDialog : public QDialog 14 | { 15 | Q_OBJECT 16 | public: 17 | TemporalSeriesDialog(GeographicalViewWidget *geoWidget, int numBins); 18 | ~TemporalSeriesDialog(); 19 | 20 | QDateTime startTime(); 21 | QDateTime endTime(); 22 | 23 | private: 24 | Ui::TemporalSeriesDialog *ui; 25 | 26 | GeographicalViewWidget *geoWidget; 27 | QList plots; 28 | 29 | public slots: 30 | void xAxisRangeChanged(const QCPRange &newRange); 31 | void timeIntervalChanged(QDateTime, QDateTime); 32 | }; 33 | 34 | #endif // TEMPORAL_SERIES_DIALOG_H 35 | -------------------------------------------------------------------------------- /src/TaxiVis/util/scalar.h: -------------------------------------------------------------------------------- 1 | #ifndef SCALAR_H 2 | #define SCALAR_H 3 | 4 | #include 5 | #include 6 | 7 | class Scalar { 8 | public: 9 | explicit Scalar( std::string name ); 10 | void store(float value); 11 | 12 | // GETTERS 13 | float min() { return _min; } 14 | float max() { return _max; } 15 | std::string name() { return _name; } 16 | int index() { return _index; } 17 | std::vector &labels() { return _labels; } 18 | 19 | // SETTERS 20 | void setMin(float min) { _min = min; } 21 | void setMax(float max) { _max = max; } 22 | void setName(std::string name) { _name = name; } 23 | void setIndex(int index) { _index = index; } 24 | 25 | private: 26 | float _min; 27 | float _max; 28 | std::string _name; 29 | int _index; 30 | std::vector _labels; 31 | }; 32 | 33 | #endif // SCALAR_H 34 | -------------------------------------------------------------------------------- /src/TaxiVis/GroupRepository.h: -------------------------------------------------------------------------------- 1 | #ifndef GROUPREPOSITORY_H 2 | #define GROUPREPOSITORY_H 3 | 4 | #include "Group.h" 5 | #include 6 | #include 7 | 8 | class GroupRepository 9 | { 10 | private: 11 | static GroupRepository *instance; 12 | private: 13 | std::vector items; 14 | 15 | public: 16 | GroupRepository(); 17 | static GroupRepository& getInstance(); 18 | const QColor& getColor(int groupId) const; 19 | QColor getQColor(int groupId) const; 20 | void addItem(const QColor& color); 21 | int getNumItems() const; 22 | const Group& getItem(int groupId) const; 23 | Group getDefaultItem(); 24 | const Group& getGroupByColor(const QColor& color); 25 | Group getNextAvailableGroup(std::set groups); 26 | }; 27 | 28 | #endif // GROUPREPOSITORY_H 29 | -------------------------------------------------------------------------------- /src/TaxiVis/RenderingLayer.cpp: -------------------------------------------------------------------------------- 1 | #include "RenderingLayer.hpp" 2 | #include 3 | 4 | RenderingLayer::RenderingLayer(bool _enabled) 5 | : enabled(_enabled) 6 | { 7 | } 8 | 9 | void RenderingLayer::setEnabled(bool b) 10 | { 11 | if (this->enabled!=b) 12 | this->enabled = b; 13 | } 14 | 15 | void RenderingLayer::useGLPainting(QPainter *painter) 16 | { 17 | if (!this->glPainting) { 18 | painter->beginNativePainting(); 19 | this->glPainting = true; 20 | } 21 | } 22 | 23 | void RenderingLayer::useQtPainting(QPainter *painter) 24 | { 25 | if (this->glPainting) { 26 | painter->endNativePainting(); 27 | this->glPainting = false; 28 | } 29 | } 30 | 31 | bool RenderingLayer::paint(QPainter *painter, bool currentGLPainting) 32 | { 33 | if (this->enabled) { 34 | this->glPainting = currentGLPainting; 35 | this->render(painter); 36 | return this->glPainting; 37 | } 38 | return currentGLPainting; 39 | } 40 | -------------------------------------------------------------------------------- /src/TaxiVis/TimeExplorationDialog.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TIME_EXPLORATION_DIALOG_H 2 | #define TIME_EXPLORATION_DIALOG_H 3 | 4 | #include 5 | #include "geographicalviewwidget.h" 6 | 7 | namespace Ui { 8 | class TimeExplorationDialog; 9 | } 10 | 11 | class TimeExplorationDialog : public QDialog 12 | { 13 | Q_OBJECT 14 | public: 15 | TimeExplorationDialog(QWidget *parent); 16 | ~TimeExplorationDialog(); 17 | 18 | void addGeoWidget(QDateTime startTime, QDateTime endTime, SelectionGraph *graph, const KdTrip::TripSet &trips); 19 | void setPlotSelection(QDateTime startTime, QDateTime endTime, SelectionGraph *graph, KdTrip::TripSet *trips); 20 | 21 | private: 22 | Ui::TimeExplorationDialog *ui; 23 | 24 | QList geoWidgets; 25 | 26 | Coordinator *coordinator; 27 | int valuesUpdated; 28 | 29 | public slots: 30 | void maxValueUpdated(float value); 31 | }; 32 | 33 | #endif // TIME_EXPLORATION_DIALOG_H 34 | -------------------------------------------------------------------------------- /src/TaxiVis/HistogramDialog.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HISTOGRAM_DIALOG_H 2 | #define HISTOGRAM_DIALOG_H 3 | 4 | #include 5 | #include "extendedhistogram.h" 6 | #include "geographicalviewwidget.h" 7 | 8 | namespace Ui { 9 | class HistogramDialog; 10 | } 11 | class ExtendedPlotWidget; 12 | class GeographicalViewWidget; 13 | 14 | class HistogramDialog : public QDialog 15 | { 16 | Q_OBJECT 17 | public: 18 | HistogramDialog(GeographicalViewWidget *geoWidget, int numBins); 19 | ~HistogramDialog(); 20 | KdTrip::TripSet * selectedTrips(); 21 | 22 | private: 23 | Ui::HistogramDialog *ui; 24 | 25 | GeographicalViewWidget *geoWidget; 26 | QList plots; 27 | KdTrip::TripSet trips; 28 | 29 | public slots: 30 | void xAxisRangeChanged(const QCPRange &newRange); 31 | void updateSelection(QList); 32 | void onFinished(int result); 33 | }; 34 | 35 | #endif // HISTOGRAM_DIALOG_H 36 | -------------------------------------------------------------------------------- /src/TaxiVis/QMapWidget.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Q_MAP_WIDGET_HPP 2 | #define Q_MAP_WIDGET_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class QMapTileWidget; 12 | class RenderingLayer; 13 | 14 | class QMapWidget : public QGraphicsView 15 | { 16 | Q_OBJECT 17 | public: 18 | QMapWidget(QWidget *parent=0); 19 | QMapWidget(QPointF coords, int level=15, QWidget *parent=0); 20 | virtual ~QMapWidget() {} 21 | 22 | QMapTileWidget *mapView() { return this->mView; } 23 | void repaintContents(); 24 | 25 | virtual void loadFinished() {} 26 | virtual void initGL() {} 27 | virtual void paintOverlay(QPainter */*painter*/) {} 28 | 29 | protected: 30 | void initWidget(QPointF coords, int level); 31 | void resizeEvent(QResizeEvent *event); 32 | void closeEvent(QCloseEvent *event); 33 | 34 | private: 35 | QMapTileWidget *mView; 36 | }; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/TaxiVis/timeselectionwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef TIMESELECTIONWIDGET_H 2 | #define TIMESELECTIONWIDGET_H 3 | 4 | #include 5 | #include 6 | #include "timewidget.h" 7 | 8 | namespace Ui { 9 | class TimeSelectionWidget; 10 | } 11 | 12 | class TimeSelectionWidget : public QWidget 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | explicit TimeSelectionWidget(QWidget *parent = 0); 18 | ~TimeSelectionWidget(); 19 | 20 | private: 21 | Ui::TimeSelectionWidget *ui; 22 | int getStepSize(); 23 | 24 | public: 25 | QDateTime getStartTime(); 26 | QDateTime getEndTime(); 27 | void setTimes(QDateTime start,QDateTime end); 28 | void setStepSize(int mins); 29 | 30 | signals: 31 | void timeUpdated(QDateTime,QDateTime); 32 | void recurrentTimeUpdated(TimeWidget *widget); 33 | void exploreInTime(const DateTimeList &timeRange); 34 | 35 | private slots: 36 | 37 | public slots: 38 | void stepBack(); 39 | void stepForward(); 40 | void timeDialogsChanged(); 41 | void exploreTime(); 42 | }; 43 | 44 | #endif // TIMESELECTIONWIDGET_H 45 | -------------------------------------------------------------------------------- /src/TaxiVis/Group.cpp: -------------------------------------------------------------------------------- 1 | #include "Group.h" 2 | #include "GroupRepository.h" 3 | 4 | /********** 5 | * Group * 6 | *********/ 7 | 8 | Group::Group() 9 | { 10 | GroupRepository gp = GroupRepository::getInstance(); 11 | *this = gp.getDefaultItem(); 12 | } 13 | 14 | Group::Group(QColor color): 15 | color(color) 16 | {} 17 | 18 | bool Group::equals(const Group& g) const{ 19 | return ((color.red() == g.color.red()) && 20 | (color.green() == g.color.green()) && 21 | (color.blue() == g.color.blue())); 22 | } 23 | 24 | const QColor &Group::getColor() const{ 25 | return color; 26 | } 27 | 28 | bool Group::operator==(const Group& g) const{ 29 | return this->equals(g); 30 | } 31 | 32 | bool Group::operator <(const Group& group) const{ 33 | QColor tempColor = group.getColor(); 34 | return ((color.red() < tempColor.red()) || 35 | (color.red() == tempColor.red() && color.green() < tempColor.green()) || 36 | (color.red() == tempColor.red() && color.green() == tempColor.green() && 37 | color.blue() < tempColor.blue()) ); 38 | } 39 | -------------------------------------------------------------------------------- /src/TaxiVis/layers/TripLocation.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TRIP_LOCATION_HPP 2 | #define TRIP_LOCATION_HPP 3 | #include "RenderingLayer.hpp" 4 | #include 5 | 6 | class GeographicalViewWidget; 7 | 8 | class TripLocation : public QObject, public RenderingLayer 9 | { 10 | Q_OBJECT 11 | public: 12 | TripLocation(GeographicalViewWidget *mw); 13 | virtual ~TripLocation(); 14 | 15 | QColor pickupColor(); 16 | void setPickupColor(QColor color); 17 | QColor dropoffColor(); 18 | void setDropoffColor(QColor color); 19 | 20 | void initGL(); 21 | void setEnabled(bool r); 22 | void render(QPainter *painter); 23 | 24 | public slots: 25 | void updateData(); 26 | 27 | protected: 28 | virtual void buildLocations(); 29 | virtual void renderGL(); 30 | 31 | bool dataReady; 32 | bool bufferDirty; 33 | GLBuffer glBuffer; 34 | std::vector vertices; 35 | PQOpenGLShaderProgram shader; 36 | QColor colorPickup; 37 | QColor colorDropoff; 38 | GeographicalViewWidget *geoWidget; 39 | }; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /src/TaxiVis/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ui_mainwindow.h" 3 | // 4 | #include "global.h" 5 | #include "GroupRepository.h" 6 | #include "viewwidget.h" 7 | 8 | #include 9 | #include 10 | 11 | MainWindow::MainWindow(QWidget *parent) : 12 | QMainWindow(parent), 13 | ui(new Ui::MainWindow) 14 | { 15 | ui->setupUi(this); 16 | 17 | // 18 | GroupRepository::getInstance(); 19 | 20 | // 21 | connect( ui->actionAddMap, SIGNAL( triggered() ), 22 | this, SLOT( addNewMap() ) ); 23 | 24 | // move( 0, 0 ); 25 | // QWidget::showMaximized(); 26 | 27 | // for to start with one map 28 | addNewMap(); 29 | ui->mdiArea->subWindowList().front()->showMaximized(); 30 | } 31 | 32 | MainWindow::~MainWindow() 33 | { 34 | delete ui; 35 | } 36 | 37 | void MainWindow::selectionChanged(){ 38 | //emit updateSelectedTrips(); 39 | } 40 | 41 | void MainWindow::addNewMap() { 42 | ViewWidget *vw = new ViewWidget( this ); 43 | QMdiSubWindow *sw = ui->mdiArea->addSubWindow( vw ); 44 | sw->show(); 45 | 46 | ui->mdiArea->tileSubWindows(); 47 | } 48 | -------------------------------------------------------------------------------- /src/TaxiVis/util/colorscale.h: -------------------------------------------------------------------------------- 1 | #ifndef COLORSCALE_H 2 | #define COLORSCALE_H 3 | 4 | #include 5 | #include 6 | 7 | using std::vector; 8 | 9 | enum ColorScaleType { 10 | PSEUDO_RAINBOW_SCALE, 11 | BLUE_TO_CYAN, 12 | BLUE_TO_YELLOW_SCALE, 13 | HEATED_OBJECTS, 14 | GRAY_SCALE, 15 | LINEAR_GRAY_SCALE, 16 | LOCS_SCALE, 17 | RAINBOW_SCALE, 18 | GREEN_TO_WHITE_SCALE, 19 | YELLOW_TO_BROWN_SCALE, 20 | DIVERGENT, 21 | SEQUENTIAL_SINGLE_HUE_RED 22 | }; 23 | 24 | class ColorScale; 25 | 26 | class ColorScaleFactory { 27 | public: 28 | static ColorScale* getInstance(ColorScaleType type); 29 | }; 30 | 31 | class ColorScale { 32 | public: 33 | ColorScale(); 34 | 35 | // main function 36 | QColor getColor(float value); 37 | 38 | // getters 39 | float max() { return _max; } 40 | float min() { return _min; } 41 | bool isReverse() { return _reverse; } 42 | 43 | // setters 44 | void setMinMax(float min, float max); 45 | void setReverse(bool reverse) { _reverse = reverse; } 46 | 47 | protected: 48 | float _min; 49 | float _max; 50 | bool _reverse; 51 | vector _colors; 52 | unsigned _levels; 53 | }; 54 | 55 | #endif // COLORSCALE_H 56 | -------------------------------------------------------------------------------- /src/TaxiVis/Selection.h: -------------------------------------------------------------------------------- 1 | #ifndef SELECTION_H 2 | #define SELECTION_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class Selection 11 | { 12 | public: 13 | enum BoundingBoxCorner{ 14 | LOWER_LEFT,LOWER_RIGHT,UPPER_LEFT,UPPER_RIGHT 15 | }; 16 | 17 | enum TYPE{ 18 | START=0, END, START_AND_END 19 | }; 20 | 21 | private: 22 | QPainterPath selectionGeometry; 23 | protected: 24 | bool active; 25 | bool selected; 26 | TYPE selectionType; 27 | public: 28 | Selection(); 29 | Selection(const QPainterPath& path); 30 | Selection(const QPainterPath& path, TYPE selectionType); 31 | ~Selection(); 32 | bool contains(QPointF p); 33 | QPainterPath getGeometry(); 34 | void getCenter(QPointF&); 35 | void translate(const QPointF& v); 36 | QRectF boundingBox(); 37 | void scaleBoundingBox(float x, float y, float w, float h); 38 | std::string str(); 39 | TYPE getType(); 40 | void setType(TYPE mode); 41 | 42 | BoundingBoxCorner getClosestCorner(float x, float y); 43 | void scale(BoundingBoxCorner,QPointF center, float dx, float dy); 44 | void setActive(bool); 45 | void toogleSetActive(); 46 | bool isActive(); 47 | }; 48 | 49 | #endif // SELECTION_H 50 | -------------------------------------------------------------------------------- /src/TaxiVis/global.h: -------------------------------------------------------------------------------- 1 | #ifndef GLOBAL_H 2 | #define GLOBAL_H 3 | 4 | #include "querymanager.h" 5 | #include "SelectionGraph.h" 6 | #include "neighborhoodset.h" 7 | #include "util/colorscale.h" 8 | 9 | struct ExtraField{ 10 | public: 11 | QString internalName; 12 | QString screenName; 13 | QString axisLabel; 14 | bool active; 15 | }; 16 | 17 | class CityMap; 18 | class Global 19 | { 20 | private: 21 | Global(); 22 | ~Global(); 23 | static Global* instance; 24 | 25 | void loadExtraFieldsData(QString filename); 26 | void loadDataYears(QString filename); 27 | private: 28 | QueryManager queryManger; 29 | CityMap* cityMap; 30 | ColorScale* colorScale; 31 | NeighborhoodSet* neighSet; 32 | // 33 | QVector extraFields; 34 | QVector dataYears; 35 | public: 36 | static Global* getInstance(); 37 | 38 | CityMap* getMap(); 39 | ColorScale* getColorScale(); 40 | NeighborhoodSet* getNeighSet(); 41 | 42 | void queryData(SelectionGraph* queryGraph, QDateTime startTime, QDateTime endTime, KdTrip::TripSet &); 43 | 44 | // 45 | int numExtraFields(); 46 | int getIndexByScreenName(QString name); 47 | ExtraField getExtraField(int index); 48 | 49 | // 50 | void getDataYears(QVector&); 51 | }; 52 | 53 | #endif // GLOBAL_H 54 | -------------------------------------------------------------------------------- /src/TaxiVis/resources.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | Resources/icons/dropoff.png 4 | Resources/icons/pickup.png 5 | Resources/icons/link.png 6 | Resources/icons/map.png 7 | Resources/icons/pickup_dropoff.png 8 | Resources/icons/animation.png 9 | Resources/icons/sync.color.png 10 | Resources/icons/sync.gray.png 11 | Resources/icons/merge.png 12 | Resources/icons/unmerge.png 13 | Resources/icons/play.png 14 | Resources/icons/pause.png 15 | Resources/icons/reset.png 16 | Resources/icons/config.png 17 | Resources/icons/config_on.png 18 | Resources/icons/time.png 19 | Resources/icons/time_on.png 20 | Resources/icons/export.png 21 | Resources/icons/explore.png 22 | 23 | Resources/shaders/paths.120.vert 24 | Resources/shaders/paths.120.geom 25 | Resources/shaders/paths.120.frag 26 | 27 | Resources/shaders/location.120.vert 28 | Resources/shaders/geo2screen.120.vert 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/TaxiVis/viewwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef VIEWWIDGET_H 2 | #define VIEWWIDGET_H 3 | 4 | #include "KdTrip.hpp" 5 | #include "SelectionGraph.h" 6 | #include "timewidget.h" 7 | 8 | #include 9 | #include 10 | 11 | namespace Ui { 12 | class ViewWidget; 13 | } 14 | class TemporalSeriesPlotWidget; 15 | class QMapWidget; 16 | class HistogramWidget; 17 | 18 | class ViewWidget : public QWidget 19 | { 20 | Q_OBJECT 21 | 22 | public: 23 | explicit ViewWidget(QWidget *parent = 0); 24 | ~ViewWidget(); 25 | 26 | // Getters 27 | TemporalSeriesPlotWidget *timeSeriesWidget(); 28 | HistogramWidget *histogramWidget(); 29 | QMapWidget *mapWidget(); 30 | 31 | private: 32 | Ui::ViewWidget *ui; 33 | 34 | KdTrip::TripSet selectedTrips; 35 | SelectionGraph selectionGraph; 36 | 37 | public slots: 38 | void geoWidgetUpdatedData(); 39 | void updateTimes(QDateTime,QDateTime); 40 | void stepBack(); 41 | void stepForward(); 42 | void setSelectionGraph(SelectionGraph* g); 43 | void plotAllAttributes(); 44 | void updateRecurrentTimes(TimeWidget*widget); 45 | 46 | private slots: 47 | void on_showMapButton_clicked(bool checked); 48 | void selectionModeChanges(int mode); 49 | void on_syncButton_clicked(bool checked); 50 | void on_showAnimationButton_clicked(bool checked); 51 | void exportTrips(); 52 | void exploreInTime(const DateTimeList &timeRange); 53 | }; 54 | 55 | #endif // VIEWWIDGET_H 56 | -------------------------------------------------------------------------------- /src/TaxiVis/util/colorbar.h: -------------------------------------------------------------------------------- 1 | #ifndef COLORBAR_H 2 | #define COLORBAR_H 3 | 4 | #include 5 | 6 | class ColorScale; 7 | class QMouseEvent; 8 | 9 | class ColorBar: public QObject { 10 | Q_OBJECT 11 | 12 | // ColorBar parameters. 13 | enum baseSize { 14 | BAR_START_X = 30, 15 | BAR_START_Y = 60, 16 | BAR_WIDTH = 20, 17 | BAR_HEIGHT = 256, 18 | TICK_WIDTH = 5, 19 | TICKS_NUM = 4, 20 | TEXT_START_X= 20, 21 | TEXT_START_Y= 80, 22 | TEXT_WIDTH = 200, 23 | TEXT_HEIGHT = 30 24 | }; 25 | 26 | public: 27 | explicit ColorBar(ColorScale *colorScale=NULL); 28 | bool contains(const QPoint &p); 29 | double getRealMin(); 30 | double getRealMax(); 31 | void setUnit(const QString &unit); 32 | 33 | signals: 34 | bool rangeSelectionChanged(double min, double max); 35 | bool rangeLimitsChanged(double min, double max); 36 | bool rangelimitsReseted(); 37 | 38 | public slots: 39 | void setColorScale(ColorScale *colorScale); 40 | void setRealMinMax(double min, double max); 41 | void paint(QPainter *painter); 42 | bool processMouseEvent(QMouseEvent *event); 43 | 44 | protected: 45 | double getRealValue(int value); 46 | 47 | private: 48 | ColorScale *_colorScale; 49 | QLinearGradient _gradient; 50 | double _minReal; 51 | double _maxReal; 52 | int _minSel; 53 | int _maxSel; 54 | bool _leftButtonPress; 55 | QString _unit; 56 | }; 57 | 58 | #endif // COLORBAR_H 59 | -------------------------------------------------------------------------------- /src/TaxiVis/timeanalysiswidget.h: -------------------------------------------------------------------------------- 1 | #ifndef TIMEANALYSISWIDGET_H 2 | #define TIMEANALYSISWIDGET_H 3 | 4 | #include 5 | #include "projectionView/pointset.h" 6 | 7 | // 8 | #include "neighborhoodgraph.h" 9 | #include 10 | 11 | namespace Ui { 12 | class TimeAnalysisWidget; 13 | } 14 | class Scalar; 15 | 16 | class TimeAnalysisWidget : public QWidget 17 | { 18 | Q_OBJECT 19 | 20 | public: 21 | explicit TimeAnalysisWidget(QWidget *parent = 0); 22 | ~TimeAnalysisWidget(); 23 | 24 | Scalar *addScalar( std::string name ); 25 | 26 | // GETTERS 27 | PointSet &lowPoints() { return _lowPoints; } 28 | PointSet &highPoints() { return _highPoints; } 29 | std::vector &scalars() { return _scalars; } 30 | Scalar *selectedScalar() { return _selectedScalar; } 31 | 32 | 33 | public slots: 34 | void changeSelectedScalar(int); 35 | void on_applyButton_clicked(); 36 | void updateLegend(); 37 | 38 | private: 39 | void loadLowAndHighData(std::string filename); 40 | void fillScalarComboBox(); 41 | 42 | void initTransitionGraphs(); 43 | 44 | private slots: 45 | void selectionModeChanges(int); 46 | private: 47 | Ui::TimeAnalysisWidget *_ui; 48 | 49 | // 50 | std::vector _scalars; 51 | PointSet _lowPoints; 52 | PointSet _highPoints; 53 | Scalar *_selectedScalar; 54 | 55 | // 56 | std::vector graphs; 57 | }; 58 | 59 | #endif // TIMEANALYSISWIDGET_H 60 | -------------------------------------------------------------------------------- /src/TaxiVis/neighborhoodgraph.cpp: -------------------------------------------------------------------------------- 1 | #include "neighborhoodgraph.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | NeighborhoodGraph::NeighborhoodGraph(int numberOfNodes): 12 | numberOfNodes(numberOfNodes){ 13 | edges.resize(numberOfNodes * numberOfNodes); 14 | } 15 | 16 | NeighborhoodGraph::NeighborhoodGraph(const std::vector &e, int numberOfNodes): 17 | numberOfNodes(numberOfNodes){ 18 | edges = e; 19 | } 20 | 21 | void NeighborhoodGraph::getBoundWeights(float &minWeight, float &maxWeight){ 22 | minWeight = INT_MAX; 23 | maxWeight = INT_MIN; 24 | 25 | int size = edges.size(); 26 | 27 | for(int i = 0 ; i < size ; ++i){ 28 | if(edges[i] < minWeight) 29 | minWeight = edges[i]; 30 | if(edges[i] > maxWeight) 31 | maxWeight = edges[i]; 32 | } 33 | } 34 | 35 | float NeighborhoodGraph::getEdge(int originIndex, int destinationIndex){ 36 | int linearIndex = originIndex * numberOfNodes + destinationIndex; 37 | int size = edges.size(); 38 | assert(0 <= linearIndex && linearIndex < size); 39 | return edges[linearIndex]; 40 | } 41 | 42 | void NeighborhoodGraph::setEdges(float v){ 43 | int size = edges.size(); 44 | for(int i = 0 ; i < size ; ++i){ 45 | edges[i] = v; 46 | } 47 | } 48 | 49 | void NeighborhoodGraph::setEdges(const vector &e){ 50 | //cout << "e.size() = " << e.size() << " edges.size() " << edges.size() << endl; 51 | assert(e.size() == edges.size()); 52 | edges = e; 53 | } 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2015, New York University 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. All advertising materials mentioning features or use of this software 12 | must display the following acknowledgement: 13 | This product includes software developed by the . 14 | 4. Neither the name of the nor the 15 | names of its contributors may be used to endorse or promote products 16 | derived from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY ''AS IS'' AND ANY 19 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 22 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /src/TaxiVis/scatterplotwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef SCATTERPLOTWIDGET_H 2 | #define SCATTERPLOTWIDGET_H 3 | 4 | #include 5 | #include 6 | #include "SelectionGraph.h" 7 | #include "KdTrip.hpp" 8 | 9 | namespace Ui { 10 | class ScatterPlotWidget; 11 | } 12 | 13 | class ScatterPlotWidget : public QWidget 14 | { 15 | Q_OBJECT 16 | public: 17 | enum ScatterPlotAttributes{FARE_AMOUNT, TIP_AMOUNT, DISTANCE, DURATION, TOLL_AMOUNT, AVG_SPEED, 18 | TIME_OF_DAY, FIELD1, FIELD2, FIELD3, FIELD4}; 19 | 20 | public: 21 | explicit ScatterPlotWidget(QWidget *parent = 0); 22 | ~ScatterPlotWidget(); 23 | 24 | void setSelectedTripsRepository(KdTrip::TripSet *); 25 | void setSelectionGraph(SelectionGraph*); 26 | void recomputePlots(); 27 | 28 | private: 29 | Ui::ScatterPlotWidget *ui; 30 | 31 | // 32 | ScatterPlotAttributes attrib1; 33 | ScatterPlotAttributes attrib2; 34 | 35 | // 36 | KdTrip::TripSet *selectedTrips; 37 | SelectionGraph *selectionGraph; 38 | 39 | // 40 | void updatePlot(); 41 | void updateAttributes(); 42 | ScatterPlotAttributes getAttrib(QString); 43 | QPointF getCoords(const KdTrip::Trip *); 44 | 45 | bool tripSatisfiesEdge(const KdTrip::Trip *trip, SelectionGraphEdge* edge); 46 | bool tripSatisfiesConstraints(const KdTrip::Trip *trip, 47 | std::vector groupNodeConstraints, 48 | std::vector groupEdgeConstraints); 49 | 50 | private slots: 51 | void setAttribute1(QString); 52 | void setAttribute2(QString); 53 | void mousePress(); 54 | void mouseWheel(); 55 | }; 56 | 57 | #endif // SCATTERPLOTWIDGET_H 58 | -------------------------------------------------------------------------------- /src/TaxiVis/QMapWidget.cpp: -------------------------------------------------------------------------------- 1 | #include "QMapWidget.hpp" 2 | #include "QMapTileWidget.hpp" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | QMapWidget::QMapWidget(QWidget *parent) 14 | : QGraphicsView(parent) 15 | { 16 | this->initWidget(QPointF(40.7566, -73.9863), 15); 17 | } 18 | 19 | QMapWidget::QMapWidget(QPointF coords, int level, QWidget *parent) 20 | : QGraphicsView(parent) 21 | { 22 | this->initWidget(coords, level); 23 | } 24 | 25 | void QMapWidget::initWidget(QPointF coords, int level) 26 | { 27 | QSurfaceFormat fmt = QSurfaceFormat::defaultFormat(); 28 | fmt.setSamples(4); 29 | 30 | QOpenGLWidget *glWidget = new QOpenGLWidget(); 31 | glWidget->setFormat(fmt); 32 | this->setViewport(glWidget); 33 | this->setFrameStyle(QFrame::NoFrame); 34 | this->setInteractive(true); 35 | 36 | this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 37 | this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 38 | 39 | QGraphicsScene *scene = new QGraphicsScene(this); 40 | this->setScene(scene); 41 | 42 | this->mView = new QMapTileWidget(coords, level, this); 43 | scene->addItem(this->mView); 44 | this->mView->setFocus(); 45 | } 46 | 47 | void QMapWidget::resizeEvent(QResizeEvent *event) 48 | { 49 | this->mView->setGeometry(QRectF(0, 0, this->width(), this->height())); 50 | this->centerOn(0.5*this->width(), 0.5*this->height()); 51 | QGraphicsView::resizeEvent(event); 52 | } 53 | 54 | void QMapWidget::closeEvent(QCloseEvent *event) 55 | { 56 | this->setViewport(NULL); 57 | QGraphicsView::closeEvent(event); 58 | } 59 | 60 | void QMapWidget::repaintContents() 61 | { 62 | this->viewport()->update(); 63 | } 64 | -------------------------------------------------------------------------------- /src/preprocess/testQuery.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../TaxiVis/KdTrip.hpp" 3 | 4 | using namespace std; 5 | 6 | int main(int argc, char** argv){ 7 | 8 | if(argc != 2){ 9 | cout << "usage: testQuery " << endl; 10 | return 0; 11 | } 12 | 13 | string fname(argv[1]); 14 | KdTrip kdtrip(fname); 15 | 16 | KdTrip::Query query; 17 | query.setPickupTimeInterval(query.createTime(2011,1,7,12,30,0), 18 | query.createTime(2014,1,7,13,10,59)); 19 | query.setDropoffTimeInterval(query.createTime(2011,1,7,12,30,0), 20 | query.createTime(2014,1,7,13,10,59)); 21 | 22 | KdTrip::QueryResult result = kdtrip.execute(query); 23 | cout << "Num Trips " << result.size() << endl; 24 | KdTrip::QueryResult::iterator it; 25 | for (it=result.begin(); it 2 | 3 | TimeWidget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 602 10 | 60 11 | 12 | 13 | 14 | 15 | 0 16 | 60 17 | 18 | 19 | 20 | 21 | 16777215 22 | 60 23 | 24 | 25 | 26 | Form 27 | 28 | 29 | 30 | 0 31 | 32 | 33 | 12 34 | 35 | 36 | 0 37 | 38 | 39 | 12 40 | 41 | 42 | 0 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | CellsWidget 61 | QWidget 62 |
timewidget.h
63 | 1 64 |
65 |
66 | 67 | 68 |
69 | -------------------------------------------------------------------------------- /src/TaxiVis/extendedhistogram.h: -------------------------------------------------------------------------------- 1 | #ifndef EXTENDEDHISTOGRAM_H 2 | #define EXTENDEDHISTOGRAM_H 3 | 4 | #include "qcustomplot.h" 5 | #include 6 | #include 7 | 8 | typedef std::pair IntervalSelection; 9 | 10 | class ExtendedHistogram : public QCustomPlot 11 | { 12 | Q_OBJECT 13 | public: 14 | enum State {IDLE,SELECTION,DRAG,SCALE}; 15 | public: 16 | ExtendedHistogram(QWidget *parent = 0); 17 | void addSelection(double selMin,double selMax); 18 | void setControlValues(double x0, double convertedValue0, 19 | double x1, double convertedValue1); 20 | QList getSelections(); 21 | void clearSelections(); 22 | protected: 23 | void paintEvent(QPaintEvent *event); 24 | void mousePressEvent(QMouseEvent *event); 25 | void mouseMoveEvent(QMouseEvent *event); 26 | void mouseReleaseEvent(QMouseEvent *event); 27 | private: 28 | QList selections; 29 | State currentState; 30 | QPointF basePoint; 31 | QPointF lastPoint; 32 | QPointF currentPoint; 33 | int currentSelectionIndex; 34 | double x0; 35 | double convertedValue0; 36 | double x1; 37 | double convertedValue1; 38 | 39 | void pickSelection(QPointF p, bool&, int &index); 40 | void convertValue(const double x, double& value); 41 | void convertSelections(QList&); 42 | void convertSelection(const double &lowerBound, const double &upperBound, 43 | IntervalSelection&); 44 | void inverseConvertSelection(const double &lowerBound, const double &upperBound, IntervalSelection &sel); 45 | void inverseConvertValue(const double x, double &value); 46 | 47 | signals: 48 | void updateSelection(QList); 49 | }; 50 | 51 | #endif // EXTENDEDHISTOGRAM_H 52 | -------------------------------------------------------------------------------- /src/preprocess/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(preprocess) 3 | 4 | # C++ standard 5 | set(CMAKE_CXX_STANDARD 11) 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 | 8 | add_definitions(-D_FILE_OFSET_BITS=64) 9 | 10 | # Find Boost 11 | set(Boost_USE_STATIC_LIBS OFF) 12 | find_package(Boost 1.42 COMPONENTS iostreams filesystem timer REQUIRED) 13 | 14 | # Find Qt5 15 | set(CMAKE_PREFIX_PATH "/opt/homebrew/opt/qt@5" CACHE PATH "Qt5 installation path") 16 | find_package(Qt5 COMPONENTS Core Gui Widgets REQUIRED) 17 | 18 | include_directories(${Boost_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) 19 | 20 | # unif96_to_bin - converts old uniform 96-byte format to binary Trip format 21 | add_executable(unif96_to_bin unif96_to_bin.cpp) 22 | target_link_libraries(unif96_to_bin ${Boost_LIBRARIES}) 23 | 24 | # sampling - spatial sampling with census tract geometry 25 | add_executable(sampling sampling.cpp) 26 | target_link_libraries(sampling Qt5::Core Qt5::Gui Qt5::Widgets ${Boost_LIBRARIES}) 27 | 28 | # csv2Binary - converts single CSV file to binary Trip format 29 | add_executable(csv2Binary csv2Binary.cpp) 30 | target_link_libraries(csv2Binary Qt5::Core ${Boost_LIBRARIES}) 31 | 32 | # newFormatCsv2Binary - converts newer CSV format to binary Trip format 33 | add_executable(newFormatCsv2Binary newFormatCsv2Binary.cpp) 34 | target_link_libraries(newFormatCsv2Binary Qt5::Core ${Boost_LIBRARIES}) 35 | 36 | # multiCsv2Binary - processes multiple CSV files listed in index file 37 | add_executable(multiCsv2Binary multiCsv2Binary.cpp) 38 | target_link_libraries(multiCsv2Binary Qt5::Core ${Boost_LIBRARIES}) 39 | 40 | # testQuery - tests KdTrip query functionality 41 | add_executable(testQuery testQuery.cpp) 42 | target_link_libraries(testQuery Qt5::Core ${Boost_LIBRARIES}) 43 | 44 | # build_kdtrip - builds KD-tree spatial index from binary Trip data 45 | add_executable(build_kdtrip build_kdtrip.cpp) 46 | target_link_libraries(build_kdtrip ${Boost_LIBRARIES}) 47 | -------------------------------------------------------------------------------- /src/TaxiVis/timewidget.h: -------------------------------------------------------------------------------- 1 | #ifndef TIMEWIDGET_H 2 | #define TIMEWIDGET_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace Ui { 11 | class TimeWidget; 12 | } 13 | 14 | typedef QPair DateTimePair; 15 | typedef QList DateTimeList; 16 | 17 | enum TimeType { 18 | DAYS = 0, 19 | HOURS, 20 | MONTHS, 21 | YEARS, 22 | INVALID 23 | }; 24 | 25 | class CellsWidget: public QWidget 26 | { 27 | Q_OBJECT 28 | 29 | public: 30 | explicit CellsWidget( QWidget *parent = 0 ); 31 | ~CellsWidget(); 32 | 33 | void setType( TimeType type ); 34 | TimeType type() const { return _type; } 35 | void changeCurrentSelection(int id) { _selecteds.push_back(id); } 36 | void getSelectedCells(bool *cells); 37 | 38 | signals: 39 | void currentCellChanged( const int, const TimeType ); 40 | 41 | protected: 42 | void paintEvent( QPaintEvent * ); 43 | void mousePressEvent ( QMouseEvent * e ); 44 | void mouseReleaseEvent ( QMouseEvent * e ); 45 | 46 | private: 47 | TimeType _type; 48 | std::vector _selecteds; 49 | std::string *_strs; 50 | int _numCells; 51 | QPoint _lastPoint; 52 | bool _mouseClick; 53 | }; 54 | 55 | class TimeWidget : public QWidget 56 | { 57 | Q_OBJECT 58 | 59 | public: 60 | explicit TimeWidget( QWidget *parent = 0 ); 61 | ~TimeWidget(); 62 | void getSelectedCells(bool *years, bool *months, bool *days, bool *hours); 63 | 64 | DateTimeList getSelectedRanges(); 65 | QList< QDate > getSelectedDays(); 66 | QList< QPair > getSelectedHours(); 67 | 68 | 69 | signals: 70 | void timeSelection( const int index, const TimeType type ); 71 | 72 | private slots: 73 | void selectionChanged( const int index, const TimeType type ); 74 | 75 | private: 76 | Ui::TimeWidget *_ui; 77 | }; 78 | 79 | #endif // TIMEWIDGET_H 80 | -------------------------------------------------------------------------------- /src/TaxiVis/Resources/shaders/paths.120.geom: -------------------------------------------------------------------------------- 1 | #version 120 2 | #extension GL_EXT_geometry_shader4 : enable 3 | 4 | uniform int zoom; 5 | uniform vec2 scale; 6 | uniform float time; 7 | uniform vec2 glyphArea; 8 | 9 | varying vec3 tex; 10 | varying float progress; 11 | 12 | void main(void) 13 | { 14 | vec4 p0 = gl_PositionIn[0]; 15 | vec4 p1 = gl_PositionIn[1]; 16 | vec4 p2 = gl_PositionIn[2]; 17 | float prevTime = time - glyphArea.x; 18 | bool stopped = ((p2.x==p2.z) && (timep2.y)); 20 | float curTime = stopped?clamp(time, p2.x, p2.y) : time; 21 | if (stopped || (curTime>=p2.x && prevTime<=p2.y)) { 22 | float w = exp2(-zoom-8.0); 23 | float width = exp2(min(zoom,18)-21.5+glyphArea.y)*w; 24 | float aspect = radians(scale.x/scale.y); 25 | vec4 dir = p1-p0; 26 | vec2 dir2 = normalize(vec2(dir.x*aspect, dir.y/aspect))*width; 27 | vec2 normal = vec2(-dir2.y, dir2.x); 28 | vec4 normalX = vec4(dir2.x/aspect, dir2.y*aspect, 0, 0); 29 | vec4 o0 = vec4(p0.xy-normal, 0, w); 30 | vec4 o1 = vec4(p0.xy+normal, 0, w); 31 | vec4 ds; 32 | float timeref; 33 | 34 | progress = (curTime-p2.z)/(p2.w-p2.z); 35 | 36 | timeref = (curTime-p2.x)/(p2.y-p2.x); 37 | ds = dir*timeref; 38 | gl_Position = o0 + ds + normalX; 39 | tex = vec3(timeref, 1, -1); 40 | EmitVertex(); 41 | gl_Position = o1 + ds + normalX; 42 | tex = vec3(timeref, 1, 1); 43 | EmitVertex(); 44 | 45 | gl_Position = o0 + ds; 46 | tex = vec3(timeref, 0, -1); 47 | EmitVertex(); 48 | gl_Position = o1 + ds; 49 | tex = vec3(timeref, 0, 1); 50 | EmitVertex(); 51 | 52 | if (stopped) 53 | ds -=normalX; 54 | else { 55 | timeref = (prevTime-p2.x)/(p2.y-p2.x); 56 | ds = dir*timeref; 57 | } 58 | gl_Position = o0 + ds; 59 | tex = vec3(timeref, -1, -1); 60 | EmitVertex(); 61 | gl_Position = o1 + ds; 62 | tex = vec3(timeref, -1, 1); 63 | EmitVertex(); 64 | 65 | EndPrimitive(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/TaxiVis/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 910 10 | 634 11 | 12 | 13 | 14 | NYC Taxi Visualization 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 0 27 | 0 28 | 910 29 | 24 30 | 31 | 32 | 33 | 34 | File 35 | 36 | 37 | 38 | 39 | Views 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | TLC Visualization 49 | 50 | 51 | TopToolBarArea 52 | 53 | 54 | false 55 | 56 | 57 | 58 | 59 | true 60 | 61 | 62 | 63 | 64 | New Map 65 | 66 | 67 | Ctrl+N 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /src/TaxiVis/coordinator.h: -------------------------------------------------------------------------------- 1 | #ifndef COORDINATOR_H 2 | #define COORDINATOR_H 3 | 4 | #include "temporalseriesplotwidget.h" 5 | #include "histogramwidget.h" 6 | 7 | #include 8 | #include 9 | 10 | class ViewWidget; 11 | class QMapTileWidget; 12 | class GeographicalViewWidget; 13 | 14 | class Coordinator : public QObject 15 | { 16 | Q_OBJECT 17 | public: 18 | explicit Coordinator(QObject *parent = 0); 19 | static Coordinator* instance(); 20 | 21 | void addView(ViewWidget *view); 22 | void addMapWidget(GeographicalViewWidget *widget); 23 | 24 | void removeView(ViewWidget *view); 25 | bool containsView(ViewWidget *view); 26 | bool containsTimeSeries(TemporalSeriesPlotWidget *plot); 27 | bool containsHist(HistogramWidget *plot); 28 | bool containsMapView(QMapTileWidget *mw); 29 | 30 | void notifyAll(); 31 | void notifyCameraChangeAll(); 32 | 33 | // set share variables 34 | void setSeriesAttribute(TemporalSeriesPlotWidget::PlotAttribute attribute) { _seriesAttribute=attribute; } 35 | void setHistsAttribute(HistogramWidget::PlotAttribute attribute) { _histsAttribute=attribute; } 36 | void setMapCenter(QPointF mapCenter) { _mapCenter = mapCenter; } 37 | void setMapLevel(int mapLevel) { _mapLevel = mapLevel; } 38 | // 39 | void stepBackward(int mins); 40 | void stepForward(int mins); 41 | 42 | QSet linkedMapViews() { return _linkedMapViews; } 43 | QSet linkedMapWidgets() { return _linkedMapWidgets; } 44 | 45 | bool isEnabled(); 46 | void setEnabled(bool b); 47 | 48 | private: 49 | 50 | bool enabled; 51 | 52 | QSet _linkedViews; 53 | QSet _linkedPlots; 54 | QSet _linkedMapViews; 55 | QSet _linkedMapWidgets; 56 | QSet _linkedHists; 57 | 58 | // For Vertical Range 59 | float _yMin; 60 | float _yMax; 61 | 62 | // For Plot Attribute 63 | TemporalSeriesPlotWidget::PlotAttribute _seriesAttribute; 64 | HistogramWidget::PlotAttribute _histsAttribute; 65 | 66 | // For Camera Information 67 | QPointF _mapCenter; 68 | int _mapLevel; 69 | 70 | static Coordinator* _instance; 71 | }; 72 | 73 | #endif // COORDINATOR_H 74 | -------------------------------------------------------------------------------- /src/TaxiVis/neighborhoodset.cpp: -------------------------------------------------------------------------------- 1 | #include "neighborhoodset.h" 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define xDEBUG 9 | 10 | NeighborhoodSet::NeighborhoodSet(){ 11 | } 12 | 13 | void NeighborhoodSet::loadGeometry(){ 14 | 15 | ifstream neighGeoFile((std::string(DATA_DIR)+"neighborhoodsGeometry.txt").c_str()); 16 | string line; 17 | int count = 0; 18 | while(getline(neighGeoFile,line)){ 19 | //cout << "Entering " << count++ << endl; 20 | if(line.size() <= 1) 21 | continue; 22 | 23 | //parse name line 24 | size_t pos = line.find_first_of(';'); 25 | string neighName = line.substr(0,pos); 26 | int numPoints = atoi(line.substr(pos+1).c_str()); 27 | QVector neighGeo; 28 | //cout << "Loading " << neighName << " " << numPoints << endl; 29 | for(int i = 0 ; i < numPoints ; ++i){ 30 | float lat, lng; 31 | neighGeoFile >> lng >> lat; 32 | //cout << " " << lat << " " << lng << endl; 33 | QPointF p(lat,lng); 34 | neighGeo.push_back(p); 35 | } 36 | Neighborhood *neigh = new Neighborhood(neighName,neighGeo); 37 | mapNamesToNeigh[neighName] = neigh; 38 | } 39 | } 40 | 41 | Neighborhood *NeighborhoodSet::getByName(string name){ 42 | assert(mapNamesToNeigh.count(name) > 0); 43 | return mapNamesToNeigh[name]; 44 | } 45 | 46 | Neighborhood* NeighborhoodSet::getNeighThatContains(const QPointF& p){ 47 | Neighborhood* container = NULL; 48 | map::iterator it; 49 | 50 | for (it = mapNamesToNeigh.begin() ; it != mapNamesToNeigh.end() ; ++it){ 51 | //cout << " Testing " << it->first << endl; 52 | Neighborhood* neighborhood = it->second; 53 | 54 | if (neighborhood->contains(p)){ 55 | container = neighborhood; 56 | break; 57 | } 58 | } 59 | 60 | return container; 61 | } 62 | 63 | int NeighborhoodSet::getNumberOfNeighborhoods(){ 64 | return mapNamesToNeigh.size(); 65 | } 66 | 67 | void NeighborhoodSet::getIterators(std::map::iterator& begin, 68 | std::map::iterator& end){ 69 | begin = mapNamesToNeigh.begin(); 70 | end = mapNamesToNeigh.end(); 71 | } 72 | -------------------------------------------------------------------------------- /src/TaxiVis/layers/HeatMap.hpp: -------------------------------------------------------------------------------- 1 | #ifndef HEAT_MAP_HPP 2 | #define HEAT_MAP_HPP 3 | #include "RenderingLayer.hpp" 4 | #include "KdTrip.hpp" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | class ColorBar; 13 | class ColorScale; 14 | class GeographicalViewWidget; 15 | 16 | class HeatMap : public QObject, public RenderingLayer 17 | { 18 | Q_OBJECT 19 | public: 20 | HeatMap(GeographicalViewWidget *mw); 21 | virtual ~HeatMap(); 22 | 23 | void setRegion(const QRectF &rect); 24 | void setResolution(const QSize &size); 25 | void setPointSize(int pointSize); 26 | 27 | float getMaxValue(); 28 | void setMaxValue(float value); 29 | 30 | 31 | void setColorScale(ColorScale *scale); 32 | ColorScale *getColorScale(); 33 | 34 | void setNormalized(bool n); 35 | bool isNormalized(); 36 | 37 | void showColorBar(bool b); 38 | bool isColorBarVisible(); 39 | 40 | virtual void setEnabled(bool r); 41 | virtual void initGL(); 42 | virtual void render(QPainter *painter); 43 | 44 | signals: 45 | void maxValueUpdated(float value); 46 | 47 | public slots: 48 | void updateData(); 49 | 50 | protected: 51 | void updateGrid(); 52 | void renderGL(); 53 | void computeVisualData(); 54 | void buildHeatMapTexture(); 55 | void updateColorBar(); 56 | 57 | QSize resolution; 58 | QRectF region; 59 | QSizeF binSize; 60 | int pointSize; 61 | GLTexture heatMapTexture; 62 | GLTexture pointTexture; 63 | QImage textureImage; 64 | QImage pointImage; 65 | 66 | std::vector binCounts; 67 | int maxBinCount; 68 | float maxValue; 69 | 70 | bool initialized; 71 | bool normalized; 72 | bool dataReady; 73 | bool textureDirty; 74 | bool visualDirty; 75 | bool colorBarVisible; 76 | 77 | PQOpenGLFramebufferObject fbo; 78 | 79 | QFont labelFont; 80 | QFontMetrics labelMetrics; 81 | ColorBar *colorBar; 82 | ColorScale *colorScale; 83 | 84 | GeographicalViewWidget *geoWidget; 85 | }; 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /src/TaxiVis/QMapView.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Q_MAP_VIEW_HPP 2 | #define Q_MAP_VIEW_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "RenderingLayer.hpp" 10 | 11 | class QMapWidget; 12 | class FpsRenderingLayer; 13 | class RenderingLayerManager; 14 | 15 | class QMapView : public QGraphicsWebView 16 | { 17 | Q_OBJECT 18 | public: 19 | QMapView(QPointF coords, int level=15, QWidget *parent=0); 20 | ~QMapView(); 21 | 22 | void setMapType(const QString &type); 23 | 24 | QPointF mapFromGeoLocation(QPointF geoCoords) const; 25 | QPointF mapToGeoLocation(QPointF viewCoords) const; 26 | 27 | int zoomLevel() const; 28 | void setZoomLevel(int level); 29 | QPointF center() const; 30 | void setCenter(QPointF p); 31 | void setView(QPointF p, int level); 32 | 33 | void showMap(bool show); 34 | void showFps(bool show); 35 | 36 | void addRenderingLayer(RenderingLayer *layer, float depth=-1); 37 | RenderingLayer* getRenderingLayer(int stackingOrder); 38 | QList getRenderingLayers(); 39 | 40 | signals: 41 | void viewChanged(QPointF center, int level); 42 | void doneUpdating(); 43 | 44 | public slots: 45 | void loadFinished(bool ok); 46 | void updateView(); 47 | void syncView(); 48 | 49 | protected: 50 | void initView(); 51 | void initGL(); 52 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); 53 | 54 | void keyPressEvent(QKeyEvent *event); 55 | void mousePressEvent(QGraphicsSceneMouseEvent *event); 56 | void mouseMoveEvent(QGraphicsSceneMouseEvent *event); 57 | void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); 58 | void resizeEvent(QGraphicsSceneResizeEvent *event); 59 | void wheelEvent(QGraphicsSceneWheelEvent *event); 60 | bool sceneEvent(QEvent *event); 61 | 62 | int getMapZoomLevel(); 63 | void setMapZoomLevel(int zoom); 64 | QPointF getMapCenter(); 65 | void setMapCenter(QPointF p); 66 | void panMapCenter(QPointF p); 67 | void invalidateZoomLevel(); 68 | 69 | private slots: 70 | void deferredLoadFinished(); 71 | 72 | private: 73 | QVariant js(const QString &cmd); 74 | bool glInitialized; 75 | bool showMapEnabled; 76 | int lastButtonPressed; 77 | QPoint lastPos; 78 | QPointF mapCenter; 79 | int mapLevel; 80 | QPointF lastCenter; 81 | int lastLevel; 82 | int startedPinchZoomLevel; 83 | QMapWidget *mapWidget; 84 | 85 | FpsRenderingLayer *fpsRenderingLayer; 86 | RenderingLayerManager *layers; 87 | }; 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /src/TaxiVis/util/colorscale.cpp: -------------------------------------------------------------------------------- 1 | #include "colorscale.h" 2 | #include "util/pseudorainbowscale.h" 3 | #include "util/bluetocyanscale.h" 4 | #include "util/bluetoyellowscale.h" 5 | #include "util/heatedobjectscale.h" 6 | #include "util/grayscale.h" 7 | #include "util/lineargrayscale.h" 8 | #include "util/locsscale.h" 9 | #include "util/rainbowscale.h" 10 | #include "util/greentowhitescale.h" 11 | #include "util/yellowtobrownscale.h" 12 | #include "util/divergent.h" 13 | #include "util/sequentialred.h" 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | ColorScale* ColorScaleFactory::getInstance(ColorScaleType type) { 20 | if (type == PSEUDO_RAINBOW_SCALE) { 21 | return new PseudoRainbowScale(); 22 | } else if (type == BLUE_TO_CYAN) { 23 | return new BlueToCyanScale(); 24 | } else if (type == BLUE_TO_YELLOW_SCALE) { 25 | return new BlueToYellowScale(); 26 | } else if (type == HEATED_OBJECTS) { 27 | return new HeatedObjectScale(); 28 | } else if (type == GRAY_SCALE) { 29 | return new GrayScale(); 30 | } else if (type == LINEAR_GRAY_SCALE) { 31 | return new LinearGrayScale(); 32 | } else if (type == LOCS_SCALE) { 33 | return new LocsScale(); 34 | } else if (type == RAINBOW_SCALE) { 35 | return new RainbowScale(); 36 | } else if (type == GREEN_TO_WHITE_SCALE) { 37 | return new GreenToWhiteScale(); 38 | } else if (type == YELLOW_TO_BROWN_SCALE) { 39 | return new YellowToBrownScale(); 40 | } else if (type == DIVERGENT) { 41 | return new Divergent(); 42 | } else if(type == SEQUENTIAL_SINGLE_HUE_RED){ 43 | return new SequentialRed(); 44 | } 45 | return NULL; 46 | } 47 | 48 | 49 | ColorScale::ColorScale(): 50 | _min(0.f), 51 | _max(1.f), 52 | _reverse(false){ 53 | } 54 | 55 | QColor ColorScale::getColor(float value) { 56 | if (_reverse) { 57 | int minindex = (int) ((_colors.size() - 1) * (1 - _min)); 58 | int maxindex = (int) ((_colors.size() - 1) * (1 - _max)); 59 | //std::cout << "index " << index << std::endl; 60 | int index = (int) (std::abs(minindex - maxindex) * (1 - value)) + maxindex; 61 | return _colors[index]; 62 | } else { 63 | int minindex = (int) ((_colors.size() - 1) * _min); 64 | int maxindex = (int) ((_colors.size() - 1) * _max); 65 | int index = (int) (round(std::abs(maxindex - minindex) * value)) + minindex; 66 | //std::cout << "index " << index << std::endl; 67 | return _colors[index]; 68 | } 69 | } 70 | 71 | void ColorScale::setMinMax(float min, float max) { 72 | assert(max >= min); 73 | _max = max; 74 | _min = min; 75 | } 76 | 77 | -------------------------------------------------------------------------------- /src/TaxiVis/layers/TripAnimationConfig.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | TripAnimationConfig 4 | 5 | 6 | 7 | 0 8 | 0 9 | 320 10 | 79 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | background: transparent; 18 | 19 | 20 | 21 | 0 22 | 23 | 24 | 0 25 | 26 | 27 | 10 28 | 29 | 30 | 0 31 | 32 | 33 | 34 | 35 | Play Speed 36 | 37 | 38 | 39 | 40 | 41 | 42 | Glyph Size 43 | 44 | 45 | 46 | 47 | 48 | 49 | Tail Length 50 | 51 | 52 | 53 | 54 | 55 | 56 | 40 57 | 58 | 59 | Qt::Horizontal 60 | 61 | 62 | 63 | 64 | 65 | 66 | 1 67 | 68 | 69 | 1000 70 | 71 | 72 | Qt::Horizontal 73 | 74 | 75 | 76 | 77 | 78 | 79 | 1 80 | 81 | 82 | 30 83 | 84 | 85 | Qt::Horizontal 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /src/TaxiVis/layers/TripAnimation.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TRIP_ANIMATION_HPP 2 | #define TRIP_ANIMATION_HPP 3 | #include "RenderingLayer.hpp" 4 | #include 5 | #include 6 | #include 7 | 8 | class GeographicalViewWidget; 9 | class QOpenGLShaderProgram; 10 | class QGraphicsProxyWidget; 11 | class QProgressDialog; 12 | namespace Ui 13 | { 14 | class TripAnimationConfig; 15 | class TripAnimationToolBar; 16 | }; 17 | 18 | class TripAnimation : public QObject, public RenderingLayer 19 | { 20 | Q_OBJECT 21 | public: 22 | TripAnimation(GeographicalViewWidget *mw); 23 | ~TripAnimation(); 24 | 25 | void initGL(); 26 | void setEnabled(bool r); 27 | void render(QPainter *painter); 28 | 29 | bool isPlaying(); 30 | void togglePlaying(); 31 | 32 | void renderGL(); 33 | void renderQt(QPainter *painter); 34 | 35 | qreal glyphSize(); 36 | void setGlyphSize(qreal size); 37 | 38 | qreal trailingPeriod(); 39 | void setTrailingPeriod(qreal seconds); 40 | 41 | int playSpeed(); 42 | 43 | int frameCount(); 44 | int currentFrame(); 45 | 46 | public slots: 47 | void play(); 48 | void stop(); 49 | void reset(); 50 | void setPlaying(bool r); 51 | void showConfig(bool r); 52 | 53 | void startNextFrame(); 54 | void updateData(); 55 | 56 | void glyphSizeSliderChanged(int); 57 | void trailingPeriodSliderChanged(int); 58 | void setCurrentFrame(int frame); 59 | void setPlaySpeed(int speed); 60 | 61 | protected: 62 | void buildAnimPath(); 63 | void updatePathBuffers(); 64 | void renderPaths(); 65 | void paintCurrentTime(QPainter *painter); 66 | 67 | void setFrameCount(int cnt); 68 | 69 | private: 70 | typedef QSharedPointer PQOpenGLShaderProgram; 71 | 72 | Ui::TripAnimationConfig *uiConfig; 73 | Ui::TripAnimationToolBar *uiToolBar; 74 | 75 | bool playing; 76 | bool pathDataReady; 77 | bool pathBufferDirty; 78 | 79 | int trafficTime; 80 | int maxTrafficTime; 81 | uint64_t globalTime; 82 | int frameInterval; 83 | QVector2D glyphArea; 84 | GLBuffer bufPath[2]; 85 | 86 | int pathGeomVertexCount; 87 | std::vector pathVertices; 88 | std::vector pathIndices; 89 | std::vector pathWeights; 90 | std::vector shaders; 91 | 92 | QFont font; 93 | GeographicalViewWidget *geoWidget; 94 | QProgressDialog *progress; 95 | QWidget *configWidget; 96 | QGraphicsProxyWidget *config; 97 | QWidget *toolBarWidget; 98 | QGraphicsProxyWidget *toolBar; 99 | }; 100 | 101 | #endif 102 | -------------------------------------------------------------------------------- /src/preprocess/merge.jl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env julia 2 | 3 | using CSV 4 | using DataFrames 5 | 6 | function main() 7 | if length(ARGS) != 3 8 | println("Usage: julia -t auto merge.jl ") 9 | println("Note: Use -t auto or -t 16 to enable multithreading") 10 | exit(1) 11 | end 12 | 13 | trip_file = ARGS[1] 14 | fare_file = ARGS[2] 15 | output_file = ARGS[3] 16 | 17 | println("Using $(Threads.nthreads()) threads") 18 | println() 19 | 20 | println("Loading trip data from: $trip_file") 21 | flush(stdout) 22 | trips = CSV.read(trip_file, DataFrame, 23 | stripwhitespace=true, 24 | buffer_in_memory=true, 25 | ntasks=Threads.nthreads()) 26 | 27 | println("Loading fare data from: $fare_file") 28 | flush(stdout) 29 | fares = CSV.read(fare_file, DataFrame, 30 | stripwhitespace=true, 31 | buffer_in_memory=true, 32 | ntasks=Threads.nthreads()) 33 | 34 | println("Trips loaded: $(nrow(trips)) rows") 35 | println("Fares loaded: $(nrow(fares)) rows") 36 | 37 | # Rename columns to remove spaces for easier access 38 | rename!(trips, strip.(names(trips))) 39 | rename!(fares, strip.(names(fares))) 40 | 41 | println("Merging data...") 42 | # Merge on medallion, hack_license, vendor_id, and pickup_datetime 43 | merged = innerjoin(trips, fares, 44 | on = [:medallion, :hack_license, :vendor_id, :pickup_datetime]) 45 | 46 | println("Merged: $(nrow(merged)) rows") 47 | 48 | # Create output dataframe with required columns 49 | println("Formatting output...") 50 | output = DataFrame( 51 | pickup_time = merged.pickup_datetime, 52 | dropoff_time = merged.dropoff_datetime, 53 | pickup_long = merged.pickup_longitude, 54 | pickup_lat = merged.pickup_latitude, 55 | dropoff_long = merged.dropoff_longitude, 56 | dropoff_lat = merged.dropoff_latitude, 57 | id_taxi = merged.medallion, 58 | distance = merged.trip_distance, 59 | fare_amount = merged.fare_amount, 60 | surcharge = merged.surcharge, 61 | mta_tax = merged.mta_tax, 62 | tip_amount = merged.tip_amount, 63 | tolls_amount = merged.tolls_amount, 64 | payment_type = merged.payment_type, 65 | passengers = merged.passenger_count, 66 | field1 = zeros(Int, nrow(merged)), 67 | field2 = zeros(Int, nrow(merged)), 68 | field3 = zeros(Int, nrow(merged)), 69 | field4 = zeros(Int, nrow(merged)) 70 | ) 71 | 72 | println("Writing output to: $output_file") 73 | CSV.write(output_file, output) 74 | 75 | println("Done! Processed $(nrow(output)) trips") 76 | end 77 | 78 | main() 79 | -------------------------------------------------------------------------------- /src/preprocess/merge.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | def validMatch(tripTokens,fareTokens): 4 | tripIndicesToMatch = [0,1,2,5] 5 | fareIndicesToMatch = [0,1,2,3] 6 | 7 | match = True 8 | 9 | for (tIndex,fIndex) in zip(tripIndicesToMatch,fareIndicesToMatch): 10 | match = match and (tripTokens[tIndex] == fareTokens[fIndex]) 11 | 12 | return match 13 | 14 | numArgs = len(sys.argv) 15 | 16 | if numArgs != 4: 17 | print("Usage: python merge.py ") 18 | exit(1) 19 | 20 | tripFileName = sys.argv[1] 21 | tripsFile = open(tripFileName) 22 | tripsHeader = tripsFile.readline() 23 | 24 | fareFileName = sys.argv[2] 25 | fareFile = open(fareFileName) 26 | faresHeader = fareFile.readline() 27 | 28 | outputFileName = sys.argv[3] 29 | outputFile = open(outputFileName,"w") 30 | 31 | #out header 32 | outputFile.write('pickup_time,dropoff_time,pickup_long,pickup_lat,dropoff_long,dropoff_lat,id_taxi,distance,fare_amount,surcharge,mta_tax,tip_amount,tolls_amount,payment_type,passengers,field1,field2,field3,field4\n') 33 | 34 | # 35 | count = 1 36 | for (tripLine,fareLine) in zip(tripsFile,fareFile): 37 | if count % 100000 == 0: 38 | print('Processed %d trips' % (count,)) 39 | tripTokens = [t.strip() for t in tripLine.split(',')] 40 | fareTokens = [t.strip() for t in fareLine.split(',')] 41 | assert(validMatch(tripTokens,fareTokens)) 42 | 43 | line = '%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,0,0,0,0\n' % (tripTokens[5] ,\ 44 | tripTokens[6] ,\ 45 | tripTokens[10],\ 46 | tripTokens[11],\ 47 | tripTokens[12],\ 48 | tripTokens[13],\ 49 | tripTokens[0] ,\ 50 | tripTokens[9] ,\ 51 | fareTokens[5] ,\ 52 | fareTokens[6] ,\ 53 | fareTokens[7] ,\ 54 | fareTokens[8] ,\ 55 | fareTokens[9] ,\ 56 | fareTokens[4] ,\ 57 | tripTokens[7]) 58 | 59 | outputFile.write(line) 60 | count += 1 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/TaxiVis/GroupRepository.cpp: -------------------------------------------------------------------------------- 1 | #include "GroupRepository.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | GroupRepository* GroupRepository::instance = 0; 10 | 11 | GroupRepository &GroupRepository::getInstance() 12 | { 13 | if (instance == 0) 14 | { 15 | instance = new GroupRepository(); 16 | 17 | string colorsFile(string(RESOURCES_DIR) + "qualitative.colors"); 18 | ifstream f(colorsFile.c_str()); 19 | if (f.is_open()) 20 | { 21 | //cout << "Reading colormap file." << endl; 22 | string line; 23 | while(getline(f, line ) ) 24 | { 25 | int r,g,b; 26 | // float coef = 0.4; 27 | if (sscanf(line.c_str(),"%d %d %d",&r,&g,&b) == 3) 28 | { 29 | QColor color(r,g,b); 30 | //assert(color != Qt::black); 31 | instance->addItem(color); 32 | // instance->addItem(QColor(coef*r + (1.0-coef), 33 | // coef*g + (1.0-coef), 34 | // coef*b + (1.0-coef))); 35 | } 36 | } 37 | } 38 | else 39 | cerr << "Could not open " << colorsFile << endl; 40 | } 41 | return *instance; 42 | } 43 | 44 | GroupRepository::GroupRepository() 45 | {} 46 | 47 | const QColor &GroupRepository::getColor(int groupId) const 48 | { 49 | assert (groupId >= 0 && groupId < static_cast(items.size())); 50 | const Group &item = items[groupId]; 51 | return item.getColor(); 52 | } 53 | 54 | QColor GroupRepository::getQColor(int groupId) const 55 | { 56 | const QColor &color = getColor(groupId); 57 | return color; 58 | } 59 | 60 | void GroupRepository::addItem(const QColor &color) 61 | { 62 | items.push_back(Group(color)); 63 | } 64 | 65 | int GroupRepository::getNumItems() const 66 | { 67 | return items.size(); 68 | } 69 | 70 | const Group &GroupRepository::getItem(int groupId) const 71 | { 72 | return items[groupId]; 73 | } 74 | 75 | Group GroupRepository::getDefaultItem(){ 76 | return items[0]; 77 | } 78 | 79 | const Group &GroupRepository::getGroupByColor(const QColor& color){ 80 | int numberOfItems = items.size(); 81 | 82 | for(int i = 0 ; i < numberOfItems ; ++i){ 83 | if(color == items.at(i).getColor()) 84 | return items.at(i); 85 | } 86 | 87 | // TODO: It needs to be corrected; 88 | return *(new Group()); 89 | } 90 | 91 | Group GroupRepository::getNextAvailableGroup(std::set groups){ 92 | int numberOfItems = items.size(); 93 | 94 | for(int i = 1; i < numberOfItems ; ++i){ 95 | Group& group = items.at(i); 96 | if(groups.count(group) == 0) 97 | return group; 98 | } 99 | 100 | return items.at(0); 101 | } 102 | -------------------------------------------------------------------------------- /src/preprocess/unif96_to_bin.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../TaxiVis/KdTrip.hpp" 4 | 5 | struct Trip { 6 | uint64_t db_idx; // 8 bytes 7 | double pick_x, pick_y; //8+8 bytes 8 | double drop_x, drop_y; //8+8 bytes 9 | uint64_t pickup_time; // 8 bytes 10 | uint64_t dropoff_time; // 8 bytes 11 | char vendor[4]; // 4 bytes 12 | uint32_t duration; // 4 bytes 13 | float miles; // 4 bytes 14 | uint32_t calc_field;//#calculated field here //4 bytes 15 | uint16_t fare; // 2 bytes 16 | uint16_t surcharge; // 2 bytes 17 | uint16_t mta_tax; // 2 bytes 18 | uint16_t tip; // 2 bytes 19 | uint16_t toll; // 2 bytes 20 | uint16_t total; // 2 bytes 21 | uint16_t medallion_id; // 2 bytes 22 | uint16_t license_id; // 2 bytes 23 | bool store_and_forward; // 1 byte 24 | uint8_t payment_type; // 2 byte 25 | uint8_t passengers; // 1 byte 26 | uint8_t rate_code; // 1 byte 27 | }; 28 | 29 | // The calc_field use the order below 30 | //0 id, 1 medallion_id, 2 license_id, 3 pick_time, 4 drop_time, 5 vendor, 6 rate_code 31 | //7 store_fwd, 8 passengers, 9 duration, 10 miles, 11 fare, 12 surcharge, 13 mta_tax 32 | //14 tip, 15 toll, 16 total, 17 payment_type, 18 19 pick_loc, 20 21 drop_loc 33 | // We want these bits to be mandatory 34 | // 0 id 35 | // 1 medallion_id 36 | // 3 pick_time 37 | // 38 | // 4 drop_time 39 | // 40 | // 9 duration 41 | // 10 miles 42 | // 11 fares 43 | // 44 | // 14 tip 45 | // 15 toll 46 | // 47 | // 16 total 48 | // 18 pick_loc 49 | // 19 pick_loc 50 | // 51 | // 20 drop_loc 52 | // 21 drop_loc 53 | // MASK = (bin)11 1101 1100 1110 0001 1011 54 | // MASK = (hex) 3 d c e 1 b 55 | // MASK = 0x3dce1b 56 | 57 | 58 | int main(int argc, char **argv) 59 | { 60 | FILE *fi = fopen(argv[1], "rb"); 61 | FILE *fo = fopen(argv[2], "wb"); 62 | int totalCount = 0; 63 | int validCount = 0; 64 | Trip t; 65 | KdTrip::Trip to; 66 | uint32_t MASK = ~0x3dce1b; 67 | while (fread(&t, 1, sizeof(t), fi)>0) { 68 | totalCount++; 69 | if ((t.calc_field & MASK)==t.calc_field) { 70 | validCount++; 71 | to.pickup_time = t.pickup_time; 72 | to.dropoff_time = t.dropoff_time; 73 | to.pickup_long = t.pick_x; 74 | to.pickup_lat = t.pick_y; 75 | to.dropoff_long = t.drop_x; 76 | to.dropoff_lat = t.drop_y; 77 | to.distance = t.miles*100; 78 | to.fare_amount = t.fare; 79 | to.surcharge = t.surcharge; 80 | to.mta_tax = t.mta_tax; 81 | to.tip_amount = t.tip; 82 | to.tolls_amount = t.toll; 83 | to.id_taxi = t.medallion_id; 84 | to.payment_type = t.payment_type; 85 | to.passengers = t.passengers; 86 | fwrite(&to, 1, sizeof(to), fo); 87 | } 88 | if (totalCount%1000000==0) { 89 | fprintf(stderr, "\r%d/%d", validCount, totalCount); 90 | } 91 | } 92 | fprintf(stderr, "\n"); 93 | fclose(fi); 94 | fclose(fo); 95 | } 96 | -------------------------------------------------------------------------------- /src/TaxiVis/histogramwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef HISTOGRAMWIDGET_H 2 | #define HISTOGRAMWIDGET_H 3 | 4 | #include 5 | #include 6 | // 7 | #include "qcustomplot.h" 8 | #include "KdTrip.hpp" 9 | #include "SelectionGraph.h" 10 | 11 | namespace Ui { 12 | class HistogramWidget; 13 | } 14 | class Coordinator; 15 | 16 | struct HistBin{ 17 | float minBin; 18 | float maxBin; 19 | float freq; 20 | HistBin(): 21 | minBin(std::numeric_limits::max()), 22 | maxBin(std::numeric_limits::min()), 23 | freq(0.0f) 24 | {} 25 | }; 26 | 27 | class HistogramWidget : public QWidget 28 | { 29 | Q_OBJECT 30 | public: 31 | enum PlotAttribute{ 32 | FARE_AMOUNT, TIP_AMOUNT, DISTANCE, DURATION, FIELD1, FIELD2, FIELD3, FIELD4 33 | }; 34 | 35 | explicit HistogramWidget(QWidget *parent = 0); 36 | ~HistogramWidget(); 37 | 38 | void setSelectedTripsRepository(KdTrip::TripSet *); 39 | void setSelectionGraph(SelectionGraph*); 40 | void setPlotAttribute(HistogramWidget::PlotAttribute pAttrib); 41 | void setNumberOfBinsOfUi(int numBins); 42 | int getNumberOfBins(); 43 | void joinSelectedTrips(KdTrip::TripSet *trips); 44 | 45 | QString getAttributeDescription(); 46 | 47 | float yMin() { return _yMin; } 48 | float yMax() { return _yMax; } 49 | PlotAttribute plotAttribute() {return _plotAttribute;} 50 | 51 | private: 52 | Ui::HistogramWidget *ui; 53 | 54 | // 55 | KdTrip::TripSet *selectedTrips; 56 | SelectionGraph *selectionGraph; 57 | 58 | // 59 | Coordinator *coordinator; 60 | 61 | // 62 | std::map > > groupHistograms; 63 | std::map > histogramDataBounds; 64 | PlotAttribute _plotAttribute; 65 | int numberOfBins; 66 | float _yMin; 67 | float _yMax; 68 | 69 | // 70 | std::map groupPlots; 71 | 72 | // 73 | void computeDataBounds(); 74 | void computeHistograms(); 75 | bool tripSatisfiesEdge(const KdTrip::Trip *trip, SelectionGraphEdge* edge); 76 | bool tripSatisfiesConstraints(const KdTrip::Trip *trip, 77 | std::vector groupNodeConstraints, 78 | std::vector groupEdgeConstraints); 79 | void updateControlValues(); 80 | 81 | // 82 | float getTripValue(const KdTrip::Trip *,PlotAttribute); 83 | 84 | public: 85 | void updatePlots(); 86 | void recomputePlots(); 87 | void updateYRange(float min, float max); 88 | 89 | public slots: 90 | void updateNumBins(); 91 | void changeHistAttribute(QString); 92 | void setNumberOfBins(int); 93 | 94 | private slots: 95 | void mousePress(QMouseEvent*); 96 | void mouseDouble(QMouseEvent*); 97 | void mouseWheel(); 98 | }; 99 | 100 | #endif // HISTOGRAMWIDGET_H 101 | -------------------------------------------------------------------------------- /src/TaxiVis/Selection.cpp: -------------------------------------------------------------------------------- 1 | #include "Selection.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "UsefulGeometryFunctions.h" 9 | 10 | using namespace std; 11 | 12 | /************** 13 | * Selection * 14 | *************/ 15 | 16 | Selection::Selection(): 17 | active(true), 18 | selectionType(Selection::START) 19 | {} 20 | 21 | Selection::Selection(const QPainterPath& path): 22 | active(true), 23 | selectionType(Selection::START){ 24 | selectionGeometry = QPainterPath(path); 25 | } 26 | 27 | Selection::Selection(const QPainterPath &path, Selection::TYPE selectionType): 28 | active(true), 29 | selectionType(selectionType){ 30 | selectionGeometry = QPainterPath(path); 31 | } 32 | 33 | Selection::~Selection(){ 34 | //cout << "Selection Destructor" << endl; 35 | } 36 | 37 | bool Selection::isActive(){ 38 | return active; 39 | } 40 | 41 | void Selection::setActive(bool x){ 42 | active = x; 43 | } 44 | 45 | void Selection::toogleSetActive(){ 46 | active = !active; 47 | } 48 | 49 | bool Selection::contains(QPointF p){ 50 | return selectionGeometry.contains(p); 51 | } 52 | 53 | QPainterPath Selection::getGeometry(){ 54 | return selectionGeometry; 55 | } 56 | 57 | void Selection::getCenter(QPointF& /*p*/){ 58 | selectionGeometry.boundingRect().center(); 59 | } 60 | 61 | void Selection::translate(const QPointF& v){ 62 | selectionGeometry.translate(v); 63 | } 64 | 65 | QRectF Selection::boundingBox(){ 66 | return selectionGeometry.boundingRect(); 67 | } 68 | 69 | void Selection::scale(BoundingBoxCorner /*corner*/,QPointF /*center*/ , float /*dx*/, float /*dy*/){ 70 | } 71 | 72 | void Selection::scaleBoundingBox(float , float , float , float ){} 73 | 74 | Selection::BoundingBoxCorner Selection::getClosestCorner(float xx, float yy){ 75 | QRectF bbox = selectionGeometry.boundingRect(); 76 | float x,y,w,h; 77 | x = bbox.x(); 78 | y = bbox.y(); 79 | w = bbox.width(); 80 | w = bbox.height(); 81 | 82 | QPointF p(xx,yy); 83 | QPointF c0(x,y+h); 84 | QPointF c1(x,y); 85 | QPointF c2(x+w,y); 86 | QPointF c3(x+w,y+h); 87 | 88 | qreal d0 = UsefulGeometry::distance(p,c0); 89 | qreal d1 = UsefulGeometry::distance(p,c1); 90 | qreal d2 = UsefulGeometry::distance(p,c2); 91 | qreal d3 = UsefulGeometry::distance(p,c3); 92 | 93 | if (d0 <= d1 && d0 <= d2 && d0 <= d3) 94 | { 95 | //distance = d0; 96 | return Selection::UPPER_LEFT; 97 | } 98 | else if (d1 <= d2 && d1 <= d3) 99 | { 100 | //distance = d1; 101 | return Selection::LOWER_LEFT; 102 | } 103 | else if (d2 <= d3) 104 | { 105 | //distance = d2; 106 | return Selection::LOWER_RIGHT; 107 | } 108 | else 109 | { 110 | //distance = d3; 111 | return Selection::UPPER_RIGHT; 112 | } 113 | 114 | } 115 | 116 | string Selection::str(){ 117 | return ""; 118 | } 119 | 120 | Selection::TYPE Selection::getType(){ 121 | return selectionType; 122 | } 123 | 124 | void Selection::setType(Selection::TYPE mode) 125 | { 126 | selectionType = mode; 127 | } 128 | 129 | -------------------------------------------------------------------------------- /process_taxi_data.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # TaxiVis Data Processing Pipeline 4 | # Processes raw NYC taxi CSV files into indexed .kdtrip format 5 | 6 | set -e # Exit on error 7 | 8 | # Colors for output 9 | RED='\033[0;31m' 10 | GREEN='\033[0;32m' 11 | YELLOW='\033[1;33m' 12 | NC='\033[0m' # No Color 13 | 14 | echo "================================================" 15 | echo "TaxiVis Data Processing Pipeline" 16 | echo "================================================" 17 | echo "" 18 | 19 | # Input files 20 | TRIP_FILE="data/2012_trip_data_1.csv" 21 | FARE_FILE="data/2012_trip_fare_1.csv" 22 | MERGED_FILE="data/2012_merged.csv" 23 | BINARY_FILE="data/2012_merged.trip" 24 | KDTRIP_FILE="data/2012_merged.kdtrip" 25 | 26 | # Check input files exist 27 | if [ ! -f "$TRIP_FILE" ]; then 28 | echo -e "${RED}Error: $TRIP_FILE not found${NC}" 29 | exit 1 30 | fi 31 | 32 | if [ ! -f "$FARE_FILE" ]; then 33 | echo -e "${RED}Error: $FARE_FILE not found${NC}" 34 | exit 1 35 | fi 36 | 37 | echo "Input files:" 38 | echo " Trip data: $TRIP_FILE ($(du -h $TRIP_FILE | cut -f1))" 39 | echo " Fare data: $FARE_FILE ($(du -h $FARE_FILE | cut -f1))" 40 | echo "" 41 | 42 | # Step 1: Merge 43 | echo -e "${GREEN}[Step 1/3] Merging trip and fare data (16 threads)...${NC}" 44 | STEP1_START=$(date +%s) 45 | julia -t 16 src/preprocess/merge.jl "$TRIP_FILE" "$FARE_FILE" "$MERGED_FILE" 46 | STEP1_END=$(date +%s) 47 | STEP1_TIME=$((STEP1_END - STEP1_START)) 48 | echo -e "${GREEN}✓ Merge completed in ${STEP1_TIME}s${NC}" 49 | echo " Output: $MERGED_FILE ($(du -h $MERGED_FILE | cut -f1))" 50 | echo "" 51 | 52 | # Step 2: Convert to binary 53 | echo -e "${GREEN}[Step 2/3] Converting CSV to binary format (16 threads)...${NC}" 54 | STEP2_START=$(date +%s) 55 | julia -t 16 src/preprocess/csv2Binary_mt.jl "$MERGED_FILE" "$BINARY_FILE" 56 | STEP2_END=$(date +%s) 57 | STEP2_TIME=$((STEP2_END - STEP2_START)) 58 | echo -e "${GREEN}✓ Binary conversion completed in ${STEP2_TIME}s${NC}" 59 | echo " Output: $BINARY_FILE ($(du -h $BINARY_FILE | cut -f1))" 60 | echo "" 61 | 62 | # Step 3: Build KD-tree index 63 | echo -e "${GREEN}[Step 3/3] Building KD-tree spatial index...${NC}" 64 | STEP3_START=$(date +%s) 65 | ./build/src/preprocess/build_kdtrip "$BINARY_FILE" "$KDTRIP_FILE" 66 | STEP3_END=$(date +%s) 67 | STEP3_TIME=$((STEP3_END - STEP3_START)) 68 | echo -e "${GREEN}✓ KD-tree indexing completed in ${STEP3_TIME}s${NC}" 69 | echo " Output: $KDTRIP_FILE ($(du -h $KDTRIP_FILE | cut -f1))" 70 | echo "" 71 | 72 | # Summary 73 | TOTAL_TIME=$((STEP1_TIME + STEP2_TIME + STEP3_TIME)) 74 | echo "================================================" 75 | echo -e "${GREEN}Pipeline completed successfully!${NC}" 76 | echo "================================================" 77 | echo "" 78 | echo "Timing Summary:" 79 | echo " Step 1 (Merge): ${STEP1_TIME}s" 80 | echo " Step 2 (CSV to Binary): ${STEP2_TIME}s" 81 | echo " Step 3 (Build KD-tree): ${STEP3_TIME}s" 82 | echo " ----------------------------------------" 83 | echo " Total: ${TOTAL_TIME}s" 84 | echo "" 85 | echo "Output files:" 86 | echo " Merged CSV: $MERGED_FILE" 87 | echo " Binary: $BINARY_FILE" 88 | echo " Indexed: $KDTRIP_FILE ← Load this in TaxiVis" 89 | echo "" 90 | echo "To use in TaxiVis, update querymanager.cpp line 10 to:" 91 | echo " std::string fname = string(DATA_DIR)+\"2012_merged.kdtrip\";" 92 | echo "" 93 | -------------------------------------------------------------------------------- /src/TaxiVis/UsefulGeometryFunctions.h: -------------------------------------------------------------------------------- 1 | #ifndef USEFULGEOMETRYFUNCTIONS_H 2 | #define USEFULGEOMETRYFUNCTIONS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | namespace UsefulGeometry{ 10 | inline qreal dotProduct(const QPointF &p1, const QPointF &p2) 11 | //!< Calculates dot product for vectors \c p1 and \c p2. 12 | { 13 | return (p1.x()*p2.x()+p1.y()*p2.y()); 14 | } 15 | 16 | inline qreal cosine(const QPointF &p1, const QPointF &p2) 17 | //! Calculates qFastCos(angle) between vectors \c p1 and \c p2. 18 | { 19 | return (dotProduct(p1,p2)/sqrt(dotProduct(p1,p1)*dotProduct(p2,p2))); 20 | } 21 | 22 | inline qreal distance(const QPointF &p1, const QPointF &p2) 23 | //! Calculates r = |p1-p2|. 24 | { 25 | return qSqrt(pow(p1.x()-p2.x(),2)+pow(p1.y()-p2.y(),2)); 26 | } 27 | 28 | inline qreal length(const QPointF &p) 29 | //! Calculates length of the vector r = |p|. 30 | { 31 | return distance(p, QPointF(0,0)); 32 | } 33 | 34 | inline qreal hillFunction(qreal sigma, qreal sigma_av) 35 | //! Hill function \frac{sigma^2}{sigma^2+sigma_{av}^2}. 36 | { 37 | return (sigma*sigma)/(sigma*sigma + sigma_av*sigma_av); 38 | } 39 | 40 | inline void drawArrow(QPainter& painter, const QPointF& p1, const QPointF& p2, qreal angle = M_PI/6) 41 | //! Draws an arrow :) 42 | { 43 | QPointF p = (p2-p1); 44 | qreal tangent = atan2(p.y(), p.x()); 45 | qreal l = sqrt(pow(p.x(),2)+pow(p.y(),2))/3; 46 | 47 | QBrush oldBrush = painter.brush(); 48 | painter.setBrush(QColor(painter.pen().color())); 49 | 50 | painter.drawLine(p1, p2); 51 | 52 | QPolygonF arrow; 53 | arrow << p2; 54 | arrow << QPointF(-l*qFastCos(tangent+angle) + p2.x(), -l*qFastSin(tangent+angle) + p2.y()); 55 | arrow << p2-p/6; 56 | arrow << QPointF(-l*qFastCos(tangent-angle) + p2.x(), -l*qFastSin(tangent-angle) + p2.y()); 57 | arrow << p2; 58 | 59 | painter.drawPolygon(arrow); 60 | 61 | painter.setBrush(oldBrush); 62 | } 63 | 64 | inline QPointF circumcenter(const QPointF &A, const QPointF &B, const QPointF &C) 65 | //! Calculates circumcenter of triangle 66 | { 67 | /* 68 | * @ C 69 | * / \ 70 | * / . \ 71 | * / O \ 72 | * A@-------@B 73 | */ 74 | 75 | qreal a = distance(B,C); 76 | qreal b = distance(A,C); 77 | qreal c = distance(B,A); 78 | 79 | QPointF O(a*A.x()+b*B.x()+c*C.x(), 80 | a*A.y()+b*B.y()+c*C.y()); 81 | O /= a+b+c; 82 | 83 | return O; 84 | } 85 | 86 | inline qreal area(const QPointF &A, const QPointF &B, const QPointF &C) 87 | //! Calculates area of triangle 88 | { 89 | //Area is 0.5*|(B-A)x(C-A)| 90 | 91 | return 0.5 * qAbs((C-A).x() * (B-A).y() - (C-A).y() * (B-A).x()); 92 | } 93 | }; 94 | 95 | inline void updateBounds(float& minValue,float& maxValue, float newValue){ 96 | if(newValue < minValue) 97 | minValue = newValue; 98 | if(newValue > maxValue) 99 | maxValue = newValue; 100 | } 101 | 102 | inline void updateBounds(std::pair& bounds, float newValue){ 103 | float& minValue = bounds.first; 104 | float& maxValue = bounds.second; 105 | if(newValue < minValue) 106 | minValue = newValue; 107 | if(newValue > maxValue) 108 | maxValue = newValue; 109 | } 110 | 111 | #endif // USEFULGEOMETRYFUNCTIONS_H 112 | -------------------------------------------------------------------------------- /src/TaxiVis/QMapTileWidget.hpp: -------------------------------------------------------------------------------- 1 | #ifndef Q_MAP_TILE_WIDGET_HPP 2 | #define Q_MAP_TILE_WIDGET_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "RenderingLayer.hpp" 13 | 14 | class QMapWidget; 15 | class FpsRenderingLayer; 16 | class RenderingLayerManager; 17 | 18 | // Represents a single map tile 19 | struct MapTile { 20 | int x, y, z; // Tile coordinates 21 | QPixmap pixmap; 22 | bool loading; 23 | 24 | MapTile() : x(0), y(0), z(0), loading(false) {} 25 | MapTile(int x, int y, int z) : x(x), y(y), z(z), loading(false) {} 26 | 27 | QString key() const { 28 | return QString("%1_%2_%3").arg(z).arg(x).arg(y); 29 | } 30 | }; 31 | 32 | class QMapTileWidget : public QGraphicsWidget 33 | { 34 | Q_OBJECT 35 | public: 36 | QMapTileWidget(QPointF coords, int level=15, QWidget *parent=0); 37 | ~QMapTileWidget(); 38 | 39 | void setMapType(const QString &type); 40 | 41 | QPointF mapFromGeoLocation(QPointF geoCoords) const; 42 | QPointF mapToGeoLocation(QPointF viewCoords) const; 43 | 44 | int zoomLevel() const; 45 | void setZoomLevel(int level); 46 | QPointF center() const; 47 | void setCenter(QPointF p); 48 | void setView(QPointF p, int level); 49 | 50 | void showMap(bool show); 51 | void showFps(bool show); 52 | 53 | void addRenderingLayer(RenderingLayer *layer, float depth=-1); 54 | RenderingLayer* getRenderingLayer(int stackingOrder); 55 | QList getRenderingLayers(); 56 | 57 | signals: 58 | void viewChanged(QPointF center, int level); 59 | void doneUpdating(); 60 | 61 | public slots: 62 | void updateView(); 63 | 64 | protected: 65 | void initGL(); 66 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); 67 | 68 | void keyPressEvent(QKeyEvent *event); 69 | void mousePressEvent(QGraphicsSceneMouseEvent *event); 70 | void mouseMoveEvent(QGraphicsSceneMouseEvent *event); 71 | void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); 72 | void resizeEvent(QGraphicsSceneResizeEvent *event); 73 | void wheelEvent(QGraphicsSceneWheelEvent *event); 74 | bool sceneEvent(QEvent *event); 75 | 76 | private: 77 | bool loadTile(int x, int y, int z); 78 | void loadVisibleTiles(); 79 | QPointF latLonToTilePixel(double lat, double lon, int zoom) const; 80 | QString getTileCachePath() const; 81 | QString getTileCacheFilePath(int x, int y, int z) const; 82 | bool loadTileFromDisk(int x, int y, int z); 83 | void saveTileToDisk(int x, int y, int z, const QPixmap &pixmap); 84 | 85 | bool glInitialized; 86 | bool showMapEnabled; 87 | int lastButtonPressed; 88 | QPoint lastPos; 89 | QPointF mapCenter; // lat, lon 90 | int mapLevel; 91 | QPointF initialCenter; // Initial center for reset 92 | int initialLevel; // Initial zoom level for reset 93 | QPointF lastCenter; 94 | int lastLevel; 95 | int startedPinchZoomLevel; 96 | QMapWidget *mapWidget; 97 | 98 | QString tileServerUrl; 99 | QString tileCachePath; 100 | QNetworkAccessManager *networkManager; 101 | QCache tileCache; 102 | 103 | FpsRenderingLayer *fpsRenderingLayer; 104 | RenderingLayerManager *layers; 105 | }; 106 | 107 | #endif 108 | -------------------------------------------------------------------------------- /src/TaxiVis/TimeExplorationDialog.cpp: -------------------------------------------------------------------------------- 1 | #include "TimeExplorationDialog.hpp" 2 | #include "ui_TimeExplorationDialog.h" 3 | #include "QMapView.hpp" 4 | #include "coordinator.h" 5 | #include "layers/HeatMap.hpp" 6 | #include "GroupRepository.h" 7 | 8 | TimeExplorationDialog::TimeExplorationDialog(QWidget *parent) 9 | : QDialog(parent), 10 | ui(new Ui::TimeExplorationDialog), 11 | valuesUpdated(0) 12 | { 13 | this->coordinator = new Coordinator(this); 14 | this->ui->setupUi(this); 15 | } 16 | 17 | TimeExplorationDialog::~TimeExplorationDialog() 18 | { 19 | for (int i=0; igeoWidgets.count(); i++) { 20 | delete this->geoWidgets.at(i)->getSelectedTrips(); 21 | delete this->geoWidgets.at(i)->getSelectionGraph(); 22 | } 23 | delete this->ui; 24 | delete this->coordinator; 25 | } 26 | 27 | void TimeExplorationDialog::addGeoWidget(QDateTime startTime, QDateTime endTime, SelectionGraph *graph, const KdTrip::TripSet &inTrips) 28 | { 29 | KdTrip::TripSet *trips = new KdTrip::TripSet(inTrips); 30 | SelectionGraph *selectionGraph = new SelectionGraph(); 31 | selectionGraph->assign(graph); 32 | 33 | GeographicalViewWidget *geoWidget = new GeographicalViewWidget(this); 34 | this->geoWidgets.append(geoWidget); 35 | this->ui->mainLayout->addWidget(geoWidget, 1); 36 | this->coordinator->addMapWidget(geoWidget); 37 | geoWidget->setCoordinator(this->coordinator); 38 | geoWidget->setSelectionTime(startTime, endTime); 39 | geoWidget->setSelectionTimeColor(GroupRepository::getInstance().getQColor(this->geoWidgets.count())); 40 | geoWidget->setSelectedTripsRepository(trips); 41 | geoWidget->setSelectionGraph(selectionGraph); 42 | geoWidget->showSelectionTime(true); 43 | 44 | HeatMap *hm = dynamic_cast(geoWidget->mapView()->getRenderingLayer(0)); 45 | hm->showColorBar(this->geoWidgets.count()==1); 46 | hm->setEnabled(true); 47 | this->connect(hm, SIGNAL(maxValueUpdated(float)), this, SLOT(maxValueUpdated(float))); 48 | 49 | geoWidget->mapView()->getRenderingLayer(1)->setEnabled(false); 50 | 51 | geoWidget->emitDatasetUpdated(); 52 | } 53 | 54 | void TimeExplorationDialog::setPlotSelection(QDateTime startTime, QDateTime endTime, SelectionGraph *graph, KdTrip::TripSet *inTrips) 55 | { 56 | // 57 | this->ui->timeSeriesWidget->setSelectedTripsRepository(inTrips); 58 | this->ui->timeSeriesWidget->setSelectionGraph(graph); 59 | this->ui->timeSeriesWidget->setDateTimes(startTime, endTime); 60 | this->ui->timeSeriesWidget->recomputePlots(); 61 | 62 | // 63 | this->ui->scatterPlotWidget->setSelectedTripsRepository(inTrips); 64 | this->ui->scatterPlotWidget->setSelectionGraph(graph); 65 | this->ui->scatterPlotWidget->recomputePlots(); 66 | 67 | // 68 | this->ui->histogramWidget->setSelectedTripsRepository(inTrips); 69 | this->ui->histogramWidget->setSelectionGraph(graph); 70 | this->ui->histogramWidget->recomputePlots(); 71 | } 72 | 73 | void TimeExplorationDialog::maxValueUpdated(float value) 74 | { 75 | valuesUpdated = (valuesUpdated+1)%this->geoWidgets.count(); 76 | if (!valuesUpdated) { 77 | float maxValue = 0; 78 | for (int i=0; igeoWidgets.count(); i++) { 79 | HeatMap *hm = dynamic_cast(this->geoWidgets.at(i)->mapView()->getRenderingLayer(0)); 80 | if (hm->getMaxValue()>maxValue) 81 | maxValue = hm->getMaxValue(); 82 | } 83 | for (int i=0; igeoWidgets.count(); i++) { 84 | HeatMap *hm = dynamic_cast(this->geoWidgets.at(i)->mapView()->getRenderingLayer(0)); 85 | hm->setMaxValue(maxValue); 86 | if (hm->isNormalized()) 87 | this->geoWidgets.at(i)->repaintContents(); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/TaxiVis/global.cpp: -------------------------------------------------------------------------------- 1 | #include "global.h" 2 | #include "CityMap.hpp" 3 | #include 4 | #include 5 | 6 | Global* Global::instance = NULL; 7 | 8 | Global::Global(){ 9 | this->cityMap = new CityMap((std::string(DATA_DIR)+"manhattan_with_weights.txt").c_str()); 10 | colorScale = ColorScaleFactory::getInstance(HEATED_OBJECTS); 11 | neighSet = new NeighborhoodSet(); 12 | neighSet->loadGeometry(); 13 | // 14 | loadExtraFieldsData((std::string(DATA_DIR)+"extra_fields.txt").c_str()); 15 | // 16 | loadDataYears((std::string(DATA_DIR)+"data_years.txt").c_str()); 17 | } 18 | 19 | Global::~Global(){ 20 | } 21 | 22 | void Global::loadExtraFieldsData(QString filename){ 23 | QFile file(filename); 24 | if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){ 25 | qDebug() << "Could not open " << filename; 26 | assert(false); 27 | } 28 | 29 | QTextStream stream(&file); 30 | extraFields.clear(); 31 | while(!stream.atEnd()){ 32 | QString line = stream.readLine(); 33 | QStringList tokens = line.split(","); 34 | assert(tokens.size() == 4); 35 | // 36 | QString internalName = tokens[0]; 37 | QString screenName = tokens[1]; 38 | QString axisLabel = tokens[2]; 39 | QString activeStr = tokens[3]; 40 | // 41 | ExtraField field; 42 | field.internalName = internalName; 43 | field.screenName = screenName; 44 | field.axisLabel = axisLabel; 45 | if(activeStr.compare("1") == 0){ 46 | field.active = true; 47 | } 48 | else{ 49 | field.active = false; 50 | } 51 | this->extraFields.push_back(field); 52 | } 53 | } 54 | 55 | void Global::loadDataYears(QString filename){ 56 | QFile file(filename); 57 | if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){ 58 | qDebug() << "Could not open " << filename; 59 | assert(false); 60 | } 61 | 62 | this->dataYears.clear(); 63 | 64 | QTextStream stream(&file); 65 | extraFields.clear(); 66 | while(!stream.atEnd()){ 67 | QString line = stream.readLine(); 68 | bool ok; 69 | int year = line.toInt(&ok); 70 | assert(ok); 71 | this->dataYears.push_back(year); 72 | } 73 | } 74 | 75 | Global *Global::getInstance(){ 76 | if(instance == NULL) 77 | instance = new Global(); 78 | 79 | return instance; 80 | } 81 | 82 | void Global::queryData(SelectionGraph* queryGraph, QDateTime startTime, QDateTime endTime, KdTrip::TripSet &resultSet){ 83 | queryManger.queryData(queryGraph,startTime,endTime,resultSet); 84 | } 85 | 86 | CityMap * Global::getMap() { 87 | return this->cityMap; 88 | } 89 | 90 | ColorScale *Global::getColorScale(){ 91 | return colorScale; 92 | } 93 | 94 | NeighborhoodSet *Global::getNeighSet(){ 95 | return neighSet; 96 | } 97 | 98 | // 99 | int Global::numExtraFields(){ 100 | return this->extraFields.size(); 101 | } 102 | 103 | int Global::getIndexByScreenName(QString name){ 104 | int index = -1; 105 | for(int i = 0 ; i < extraFields.size() ; ++i){ 106 | ExtraField field = extraFields.at(i); 107 | if(field.screenName.compare(name) == 0){ 108 | index = i; 109 | break; 110 | } 111 | } 112 | return index; 113 | } 114 | 115 | ExtraField Global::getExtraField(int index){ 116 | return this->extraFields.at(index); 117 | } 118 | 119 | void Global::getDataYears(QVector& result){ 120 | result.clear(); 121 | result = dataYears; 122 | } 123 | -------------------------------------------------------------------------------- /src/TaxiVis/RenderingLayer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef RENDERING_LAYER_HPP 2 | #define RENDERING_LAYER_HPP 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class QPainter; 11 | class RenderingLayer; 12 | typedef QSharedPointer PQOpenGLShaderProgram; 13 | typedef QSharedPointer PQOpenGLFramebufferObject; 14 | 15 | class RenderingLayer 16 | { 17 | public: 18 | RenderingLayer(bool enabled=true); 19 | virtual ~RenderingLayer() {} 20 | 21 | bool isEnabled(); 22 | void toggleEnabled(); 23 | 24 | bool isGLPainting(); 25 | void useGLPainting(QPainter *painter); 26 | void useQtPainting(QPainter *painter); 27 | 28 | bool paint(QPainter *painter, bool currentGLPainting=false); 29 | 30 | virtual void setEnabled(bool b); 31 | virtual void initGL() {} 32 | 33 | virtual void render(QPainter *painter) = 0; 34 | 35 | protected: 36 | bool enabled; 37 | 38 | private: 39 | bool glPainting; 40 | }; 41 | 42 | struct GLBuffer 43 | { 44 | GLBuffer(): buffer(0), size(0) {} 45 | 46 | void generate() { 47 | glGenBuffers(1, &this->buffer); 48 | this->size = 0; 49 | } 50 | 51 | void setData(GLenum target, GLsizeiptr dataSize, const GLvoid* data, GLenum usage) 52 | { 53 | glBindBuffer(target, this->buffer); 54 | if (this->sizesize = dataSize; 57 | } 58 | glBufferSubData(target, 0, dataSize, data); 59 | } 60 | 61 | GLuint buffer; 62 | GLsizeiptr size; 63 | }; 64 | 65 | struct GLTexture 66 | { 67 | void bind() 68 | { 69 | if (!this->size.isValid()) { 70 | glGenTextures(1, &this->id); 71 | glBindTexture(GL_TEXTURE_2D, this->id); 72 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 73 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 74 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 75 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 76 | glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 77 | } 78 | else 79 | glBindTexture(GL_TEXTURE_2D, this->id); 80 | } 81 | 82 | void ensureSize(const QSize &newSize) 83 | { 84 | if (!this->size.isValid() || 85 | this->size.width()size.height()size = QSize(std::max(this->size.width(), newSize.width()), 88 | std::max(this->size.height(), newSize.height())); 89 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 90 | this->size.width(), this->size.height(), 91 | 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); 92 | } 93 | } 94 | 95 | void setImage(const QImage &img) 96 | { 97 | QImage texImg = img.convertToFormat(QImage::Format_RGBA8888).mirrored(); 98 | this->bind(); 99 | this->ensureSize(texImg.size()); 100 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 101 | texImg.width(), texImg.height(), 102 | GL_RGBA, GL_UNSIGNED_BYTE, texImg.constBits()); 103 | 104 | } 105 | 106 | GLuint id; 107 | QSize size; 108 | }; 109 | 110 | inline bool RenderingLayer::isEnabled() 111 | { 112 | return this->enabled; 113 | } 114 | 115 | inline void RenderingLayer::toggleEnabled() 116 | { 117 | this->setEnabled(!this->enabled); 118 | } 119 | 120 | inline bool RenderingLayer::isGLPainting() 121 | { 122 | return this->glPainting; 123 | } 124 | 125 | #endif 126 | -------------------------------------------------------------------------------- /src/TaxiVis/HistogramDialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | HistogramDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1350 10 | 800 11 | 12 | 13 | 14 | Attribute Exploration 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 0 24 | 0 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 0 34 | 0 35 | 36 | 37 | widget_4 38 | 39 | 40 | 41 | 42 | 43 | 44 | 0 45 | 0 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 0 55 | 0 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | Qt::Horizontal 66 | 67 | 68 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | HistogramWidget 77 | QWidget 78 |
histogramwidget.h
79 | 1 80 |
81 |
82 | 83 | 84 | 85 | buttonBox 86 | accepted() 87 | HistogramDialog 88 | accept() 89 | 90 | 91 | 248 92 | 254 93 | 94 | 95 | 157 96 | 274 97 | 98 | 99 | 100 | 101 | buttonBox 102 | rejected() 103 | HistogramDialog 104 | reject() 105 | 106 | 107 | 316 108 | 260 109 | 110 | 111 | 286 112 | 274 113 | 114 | 115 | 116 | 117 |
118 | -------------------------------------------------------------------------------- /src/TaxiVis/TimeExplorationDialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | TimeExplorationDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1280 10 | 850 11 | 12 | 13 | 14 | Paremeter Exploration In Time 15 | 16 | 17 | 18 | 0 19 | 20 | 21 | 22 | 23 | Qt::Vertical 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 0 32 | 250 33 | 34 | 35 | 36 | 0 37 | 38 | 39 | 40 | Time Serie 41 | 42 | 43 | 44 | 45 | Histogram 46 | 47 | 48 | 49 | 50 | ScatterPlot 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | Qt::Horizontal 60 | 61 | 62 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | TemporalSeriesPlotWidget 71 | QWidget 72 |
temporalseriesplotwidget.h
73 | 1 74 |
75 | 76 | HistogramWidget 77 | QWidget 78 |
histogramwidget.h
79 | 1 80 |
81 | 82 | ScatterPlotWidget 83 | QWidget 84 |
scatterplotwidget.h
85 | 1 86 |
87 |
88 | 89 | 90 | 91 | buttonBox 92 | accepted() 93 | TimeExplorationDialog 94 | accept() 95 | 96 | 97 | 248 98 | 254 99 | 100 | 101 | 157 102 | 274 103 | 104 | 105 | 106 | 107 | buttonBox 108 | rejected() 109 | TimeExplorationDialog 110 | reject() 111 | 112 | 113 | 316 114 | 260 115 | 116 | 117 | 286 118 | 274 119 | 120 | 121 | 122 | 123 |
124 | -------------------------------------------------------------------------------- /src/TaxiVis/layers/Triangulator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "Triangulator.hpp" 7 | 8 | namespace Triangulator 9 | { 10 | 11 | static const double EPSILON=1e-20; 12 | 13 | double Triangulate::Area(const Vector2dVector &contour) 14 | { 15 | 16 | int n = contour.size(); 17 | 18 | double A=0.0; 19 | 20 | for(int p=n-1,q=0; q= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f)); 52 | }; 53 | 54 | bool Triangulate::Snip(const Vector2dVector &contour,int u,int v,int w,int n,int *V) 55 | { 56 | int p; 57 | double Ax, Ay, Bx, By, Cx, Cy, Px, Py; 58 | 59 | Ax = contour[V[u]].GetX(); 60 | Ay = contour[V[u]].GetY(); 61 | 62 | Bx = contour[V[v]].GetX(); 63 | By = contour[V[v]].GetY(); 64 | 65 | Cx = contour[V[w]].GetX(); 66 | Cy = contour[V[w]].GetY(); 67 | 68 | if ( EPSILON > (((Bx-Ax)*(Cy-Ay)) - ((By-Ay)*(Cx-Ax))) ) return false; 69 | 70 | for (p=0;p2; ) 103 | { 104 | /* if we loop, it is probably a non-simple polygon */ 105 | if (0 >= (count--)) 106 | { 107 | //** Triangulate: ERROR - probable bad polygon! 108 | return false; 109 | } 110 | 111 | /* three consecutive vertices in current polygon, */ 112 | int u = v ; if (nv <= u) u = 0; /* previous */ 113 | v = u+1; if (nv <= v) v = 0; /* new v */ 114 | int w = v+1; if (nv <= w) w = 0; /* next */ 115 | 116 | if ( Snip(contour,u,v,w,nv,V) ) 117 | { 118 | int a,b,c,s,t; 119 | 120 | /* true names of the vertices */ 121 | a = V[u]; b = V[v]; c = V[w]; 122 | 123 | /* output Triangle */ 124 | result.push_back( contour[a] ); 125 | result.push_back( contour[b] ); 126 | result.push_back( contour[c] ); 127 | 128 | m++; 129 | 130 | /* remove v from remaining polygon */ 131 | for(s=v,t=v+1;t 2 | 3 | TemporalSeriesDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1440 10 | 800 11 | 12 | 13 | 14 | Attribute Exploration 15 | 16 | 17 | 18 | 19 | 20 | 0 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | Qt::Horizontal 70 | 71 | 72 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | TemporalSeriesPlotWidget 81 | QWidget 82 |
temporalseriesplotwidget.h
83 | 1 84 |
85 |
86 | 87 | 88 | 89 | buttonBox 90 | accepted() 91 | TemporalSeriesDialog 92 | accept() 93 | 94 | 95 | 248 96 | 254 97 | 98 | 99 | 157 100 | 274 101 | 102 | 103 | 104 | 105 | buttonBox 106 | rejected() 107 | TemporalSeriesDialog 108 | reject() 109 | 110 | 111 | 316 112 | 260 113 | 114 | 115 | 286 116 | 274 117 | 118 | 119 | 120 | 121 |
122 | -------------------------------------------------------------------------------- /src/TaxiVis/extendedplotwidget.cpp: -------------------------------------------------------------------------------- 1 | #include "extendedplotwidget.h" 2 | #include 3 | 4 | QDateTime dateTimeFromTimet(time_t t){ 5 | struct tm* st_tm = localtime (&t); 6 | return QDateTime(QDate(st_tm->tm_year + 1900, 7 | st_tm->tm_mon + 1, 8 | st_tm->tm_mday), 9 | QTime(st_tm->tm_hour, 10 | st_tm->tm_min, 11 | st_tm->tm_sec)); 12 | } 13 | 14 | ExtendedPlotWidget::ExtendedPlotWidget(QWidget *parent) : 15 | QCustomPlot(parent), 16 | currentState(IDLE) 17 | { 18 | this->setRangeDrag(Qt::Horizontal | Qt::Vertical); 19 | this->setRangeZoom(Qt::Horizontal | Qt::Vertical); 20 | this->setMouseTracking(true); 21 | buttonPressed = false; 22 | } 23 | 24 | void ExtendedPlotWidget::paintEvent(QPaintEvent *event){ 25 | QCustomPlot::paintEvent(event); 26 | 27 | // 28 | QPainter painter(this); 29 | if(currentState == SELECTION){ 30 | QPen pen; 31 | pen.setColor(Qt::gray); 32 | QColor color = Qt::gray; 33 | color.setAlphaF(0.3); 34 | painter.setPen(pen); 35 | painter.setBrush(color); 36 | 37 | qreal x,y,w,h; 38 | x = std::min(lastPoint.x(),currentPoint.x()); 39 | y = 0; 40 | w = std::max(lastPoint.x(),currentPoint.x()) - x; 41 | h = height(); 42 | 43 | // // 44 | // qDebug() << "Points " << lastPoint << " " << currentPoint << " " 45 | // << xAxis->pixelToCoord(x) << " " << xAxis->pixelToCoord(x+w); 46 | 47 | 48 | // QDateTime start = QDateTime::fromMSecsSinceEpoch(xAxis->pixelToCoord(x)*1000 + 3600); 49 | // QDateTime end = QDateTime::fromMSecsSinceEpoch(xAxis->pixelToCoord(x+w)*1000 + 3600); 50 | 51 | // qDebug() << "Start " << start << " end " << end; 52 | 53 | painter.drawRect(QRectF(x,y,w,h)); 54 | } 55 | 56 | if(underMouse()){ 57 | QPen pen; 58 | pen.setColor(Qt::gray); 59 | QColor color = Qt::gray; 60 | color.setAlphaF(0.3); 61 | painter.setPen(pen); 62 | painter.setBrush(color); 63 | 64 | time_t t = xAxis->pixelToCoord(mousePosition.x()); 65 | QDateTime mousePosTime = dateTimeFromTimet(t); 66 | 67 | painter.drawLine(mousePosition.x(),0,mousePosition.x(),height()); 68 | 69 | int x = mousePosition.x()-180; 70 | if(x < 0) 71 | x += 190; 72 | painter.drawText(x,mousePosition.y(),180,20,0,mousePosTime.toString()); 73 | } 74 | } 75 | 76 | void ExtendedPlotWidget::mousePressEvent(QMouseEvent *event){ 77 | if(event->button() & Qt::RightButton){ 78 | //draw selection 79 | lastPoint = event->pos(); 80 | currentPoint = lastPoint; 81 | currentState = SELECTION; 82 | repaint(); 83 | } 84 | else{ 85 | buttonPressed = true; 86 | QCustomPlot::mousePressEvent(event); 87 | } 88 | } 89 | 90 | void ExtendedPlotWidget::mouseMoveEvent(QMouseEvent *event){ 91 | // 92 | mousePosition = event->pos(); 93 | if(currentState == SELECTION){ 94 | currentPoint = event->pos(); 95 | repaint(); 96 | } 97 | else if(buttonPressed){ 98 | QCustomPlot::mouseMoveEvent(event); 99 | } 100 | else{ 101 | repaint(); 102 | } 103 | 104 | } 105 | 106 | void ExtendedPlotWidget::mouseReleaseEvent(QMouseEvent *event){ 107 | if(currentState == SELECTION){ 108 | currentState = IDLE; 109 | 110 | qreal x,y,w,h; 111 | x = std::min(lastPoint.x(),currentPoint.x()); 112 | y = 0; 113 | w = std::max(lastPoint.x(),currentPoint.x()) - x; 114 | h = height(); 115 | 116 | QDateTime start = dateTimeFromTimet(xAxis->pixelToCoord(x)); 117 | QDateTime end = dateTimeFromTimet(xAxis->pixelToCoord(x+w)); 118 | 119 | emit timeIntervalChanged(start,end); 120 | 121 | repaint(); 122 | } 123 | else{ 124 | QCustomPlot::mouseReleaseEvent(event); 125 | } 126 | 127 | buttonPressed = false; 128 | } 129 | 130 | void ExtendedPlotWidget::leaveEvent(QEvent *){ 131 | repaint(); 132 | } 133 | -------------------------------------------------------------------------------- /src/preprocess/newFormatCsv2Binary.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../TaxiVis/KdTrip.hpp" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | int main(int argc, char** argv){ 15 | if(argc != 3){ 16 | cout << "usage: ./newFormatCsv2Binary " << endl; 17 | return -1; 18 | } 19 | 20 | // 21 | QString inputFilename = argv[1]; 22 | QString outputFilename = argv[2]; 23 | QFile file(inputFilename); 24 | 25 | if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { 26 | cout << "Could not open file: " << inputFilename.toStdString() << endl; 27 | return -1; 28 | } 29 | 30 | //ignore header 31 | QTextStream textStream(&file); 32 | QString header = textStream.readLine(); 33 | #ifdef DEBUG 34 | qDebug() << "Header: " << header; 35 | qDebug() << " Num Fields " << header.split(",").size(); 36 | #endif 37 | 38 | // 39 | QFile outputFile(outputFilename); 40 | if (!outputFile.open(QIODevice::WriteOnly)) { 41 | cout << "Could not write file: " << outputFilename.toStdString() << endl; 42 | return -1; 43 | } 44 | 45 | // 46 | int count = 1; 47 | 48 | while(!textStream.atEnd()){ 49 | QString line; 50 | QStringList tokens; 51 | 52 | if(count % 10000 == 0){ 53 | cout << "Processed " << count << " trips" << endl; 54 | } 55 | 56 | // 57 | line = textStream.readLine(); 58 | tokens = line.split(','); 59 | 60 | // 61 | KdTrip::Trip myTrip = {0}; 62 | QDateTime pickupDateTime = QDateTime::fromString(tokens[1],"yyyy-MM-dd HH:mm:ss"); 63 | QDateTime dropoffDateTime = QDateTime::fromString(tokens[2],"yyyy-MM-dd HH:mm:ss"); 64 | 65 | 66 | myTrip.pickup_time = pickupDateTime.toMSecsSinceEpoch()/1000;//KdTrip::Query::createTime(2011,5,1,8,1,55); 67 | myTrip.dropoff_time = dropoffDateTime.toMSecsSinceEpoch()/1000;//KdTrip::Query::createTime(2011,5,1,9,0,0); 68 | 69 | // 70 | myTrip.passengers = tokens[3].toUInt(); 71 | myTrip.distance = (uint16_t)(tokens[4].toFloat() * 100); 72 | 73 | // 74 | myTrip.pickup_long = tokens[5].toFloat(); 75 | myTrip.pickup_lat = tokens[6].toFloat(); 76 | // 77 | myTrip.dropoff_long = tokens[9].toFloat(); 78 | myTrip.dropoff_lat = tokens[10].toFloat(); 79 | 80 | // 81 | uint8_t paymentType = 0; 82 | myTrip.payment_type = tokens[11].toUInt(); 83 | 84 | // 85 | myTrip.fare_amount = (uint16_t)(tokens[12].toFloat() * 100); 86 | myTrip.surcharge = (uint16_t)(tokens[13].toFloat() * 100); 87 | myTrip.mta_tax = (uint16_t)(tokens[14].toFloat() * 100); 88 | myTrip.tip_amount = (uint16_t)(tokens[15].toFloat() * 100); 89 | myTrip.tolls_amount = (uint16_t)(tokens[16].toFloat() * 100); 90 | 91 | // 92 | myTrip.id_taxi = 1; 93 | 94 | // 95 | myTrip.field1 = 0; 96 | myTrip.field2 = 0; 97 | myTrip.field3 = 0; 98 | myTrip.field4 = 0; 99 | 100 | // 101 | #ifdef DEBUG 102 | qDebug() << "Line:" << line; 103 | cout << " Taxi ID " << myTrip.id_taxi << endl; 104 | cout << " pickup_long " << myTrip.pickup_long << endl; 105 | cout << " pickup_lat " << myTrip.pickup_lat << endl; 106 | cout << " dropoff_long " << myTrip.dropoff_long << endl; 107 | cout << " dropoff_lat " << myTrip.pickup_lat << endl; 108 | cout << " fare " << myTrip.fare_amount << endl; 109 | cout << " distance " << myTrip.distance << endl; 110 | cout << " field 1 " << myTrip.field1 << endl; 111 | #endif 112 | 113 | // 114 | outputFile.write((char*)&myTrip,sizeof(KdTrip::Trip)); 115 | 116 | // 117 | ++count; 118 | } 119 | outputFile.close(); 120 | 121 | cout << "Wrote " << count << " trips" << endl; 122 | cout << " Size of trip " << sizeof(KdTrip::Trip) << endl; 123 | cout << " Total Size " << count * sizeof(KdTrip::Trip) << endl; 124 | 125 | return 0; 126 | } 127 | -------------------------------------------------------------------------------- /src/TaxiVis/SelectionGraph.h: -------------------------------------------------------------------------------- 1 | #ifndef SELECTIONGRAPH_H 2 | #define SELECTIONGRAPH_H 3 | 4 | #include "Selection.h" 5 | #include "Group.h" 6 | #include 7 | 8 | class SelectionGraphEdge; 9 | 10 | class SelectionGraphNode{ 11 | private: 12 | int id; 13 | std::vector inEdges; 14 | std::vector outEdges; 15 | Selection *selection; 16 | Group group; 17 | 18 | // 19 | bool selected;//used for gui interaction 20 | 21 | // 22 | static int nextNodeID; 23 | public: 24 | SelectionGraphNode(); 25 | SelectionGraphNode(Selection*,Group group); 26 | SelectionGraphNode(SelectionGraphNode*); 27 | ~SelectionGraphNode(); 28 | int getId(); 29 | int inDegree(); 30 | SelectionGraphEdge* getInEdge(int index); 31 | int outDegree(); 32 | SelectionGraphEdge* getOutEdge(int index); 33 | std::string str(); 34 | void addInEdge(SelectionGraphEdge*);//TODO:Ensure that the graph is simple 35 | void addOutEdge(SelectionGraphEdge*);//TODO:Ensure that the graph is simple 36 | void removeInEdge(int edgeID); 37 | void removeOutEdge(int edgeID); 38 | Selection* getSelection(); 39 | Group getGroup(); 40 | void setGroup(const Group &); 41 | void copyGroupToNeighbors(); 42 | // 43 | void setSelected(bool); 44 | void toogleSelected(); 45 | bool isSelected(); 46 | }; 47 | 48 | class SelectionGraphEdge{ 49 | private: 50 | int id; 51 | SelectionGraphNode* tail; 52 | SelectionGraphNode* head; 53 | Group group; 54 | 55 | // 56 | bool selected;//used for gui interaction 57 | 58 | // 59 | static int nextEdgeID; 60 | public: 61 | SelectionGraphEdge(SelectionGraphNode* tail,SelectionGraphNode* head,Group group); 62 | ~SelectionGraphEdge(); 63 | SelectionGraphNode* getTail(); 64 | SelectionGraphNode* getHead(); 65 | SelectionGraphNode* opposite(SelectionGraphNode*); 66 | int getID(); 67 | std::string std(); 68 | Group getGroup(); 69 | void setGroup(Group group); 70 | // 71 | void setSelected(bool); 72 | void toogleSelected(); 73 | bool isSelected(); 74 | }; 75 | 76 | class SelectionGraph{ 77 | private: 78 | std::map nodes; 79 | std::map edges; 80 | public: 81 | public: 82 | typedef std::map::iterator NodeIterator; 83 | typedef std::map::reverse_iterator NodeReverseIterator; 84 | typedef std::map::iterator EdgeIterator; 85 | public: 86 | SelectionGraph(); 87 | ~SelectionGraph(); 88 | SelectionGraphNode* addNode(); 89 | SelectionGraphNode* addNode(Selection *); 90 | void addNode(SelectionGraphNode *); 91 | SelectionGraphEdge* addEdge(); 92 | SelectionGraphEdge* addEdge(SelectionGraphNode* tail,SelectionGraphNode* head); 93 | void assign(SelectionGraph *); 94 | 95 | SelectionGraphNode* getNodeByID(int nodeID); 96 | void getNodeIterator(NodeIterator& begin, NodeIterator& end); 97 | void getNodeReverseIterator(NodeReverseIterator& begin,NodeReverseIterator& end); 98 | 99 | void getEdgeIterator(EdgeIterator& begin, EdgeIterator& end); 100 | 101 | void removeNode(int nodeID); 102 | 103 | SelectionGraphEdge* getEdgeByID(int edgeID); 104 | void removeEdge(int edgeID); 105 | std::string str(); 106 | 107 | int numberOfNodes(); 108 | int numberOfEdges(); 109 | 110 | bool isEmpty(); 111 | 112 | // 113 | void groupNodesAndEdgeByColor(std::set& groups, 114 | std::map >& mapGroupToNodes, 115 | std::map >& mapGroupToEdges); 116 | }; 117 | 118 | #endif // SELECTIONGRAPH_H 119 | -------------------------------------------------------------------------------- /src/TaxiVis/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | if(POLICY_LEVEL) 3 | cmake_policy(VERSION 3.5) 4 | endif() 5 | set(CMAKE_BUILD_TYPE Release CACHE STRING "Set build type.") 6 | project(TaxiVis) 7 | 8 | # General definitions 9 | add_definitions(-D_FILE_OFSET_BITS=64) 10 | add_definitions(-DRESOURCES_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/Resources/\") 11 | add_definitions(-DDATA_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/../../data/\") 12 | 13 | # Project files 14 | set(QT_HEADERS 15 | # HistogramDialog.hpp 16 | # TemporalSeriesDialog.hpp 17 | # TimeExplorationDialog.hpp 18 | QMapTileWidget.hpp 19 | QMapWidget.hpp 20 | coordinator.h 21 | extendedhistogram.h 22 | extendedplotwidget.h 23 | geographicalviewwidget.h 24 | histogramwidget.h 25 | layers/GridMap.hpp 26 | layers/HeatMap.hpp 27 | layers/TripAnimation.hpp 28 | layers/TripLocation.hpp 29 | layers/TripLocationLOD.hpp 30 | mainwindow.h 31 | qcustomplot.h 32 | scatterplotwidget.h 33 | temporalseriesplotwidget.h 34 | timeselectionwidget.h 35 | util/colorbar.h 36 | viewwidget.h 37 | timewidget.h 38 | ) 39 | 40 | set(FORMS 41 | # HistogramDialog.ui 42 | # TemporalSeriesDialog.ui 43 | # TimeExplorationDialog.ui 44 | histogramwidget.ui 45 | layers/TripAnimationConfig.ui 46 | layers/TripAnimationToolBar.ui 47 | mainwindow.ui 48 | scatterplotwidget.ui 49 | temporalseriesplotwidget.ui 50 | timeselectionwidget.ui 51 | viewwidget.ui 52 | timewidget.ui 53 | ) 54 | 55 | set(SOURCES 56 | # HistogramDialog.cpp 57 | # TemporalSeriesDialog.cpp 58 | # TimeExplorationDialog.cpp 59 | Group.cpp 60 | GroupRepository.cpp 61 | QMapTileWidget.cpp 62 | QMapWidget.cpp 63 | RenderingLayer.cpp 64 | Selection.cpp 65 | SelectionGraph.cpp 66 | coordinator.cpp 67 | extendedhistogram.cpp 68 | extendedplotwidget.cpp 69 | geographicalviewwidget.cpp 70 | global.cpp 71 | histogramwidget.cpp 72 | layers/GridMap.cpp 73 | layers/HeatMap.cpp 74 | layers/Triangulator.cpp 75 | layers/TripAnimation.cpp 76 | layers/TripLocation.cpp 77 | layers/TripLocationLOD.cpp 78 | main.cpp 79 | mainwindow.cpp 80 | neighborhood.cpp 81 | neighborhoodgraph.cpp 82 | neighborhoodset.cpp 83 | qcustomplot.cpp 84 | querymanager.cpp 85 | scatterplotwidget.cpp 86 | temporalseriesplotwidget.cpp 87 | timeselectionwidget.cpp 88 | util/bluetocyanscale.cpp 89 | util/bluetoyellowscale.cpp 90 | util/colorbar.cpp 91 | util/colorscale.cpp 92 | util/divergent.cpp 93 | util/grayscale.cpp 94 | util/greentowhitescale.cpp 95 | util/heatedobjectscale.cpp 96 | util/lineargrayscale.cpp 97 | util/locsscale.cpp 98 | util/pseudorainbowscale.cpp 99 | util/rainbowscale.cpp 100 | util/scalar.cpp 101 | util/sequentialred.cpp 102 | util/yellowtobrownscale.cpp 103 | viewwidget.cpp 104 | timewidget.cpp 105 | # timeanalysiswidget.cpp 106 | ) 107 | set(RESOURCES resources.qrc) 108 | 109 | 110 | # Find Boost 111 | set(Boost_USE_STATIC_LIBS OFF) 112 | set(Boost_NO_BOOST_CMAKE ON) 113 | find_package(Boost 1.42 REQUIRED COMPONENTS iostreams filesystem timer) 114 | 115 | # Find OpenGL 116 | find_package(OpenGL REQUIRED) 117 | 118 | # Find GLEW 119 | find_library(GLEW_LIBRARY NAMES GLEW glew PATHS /opt/homebrew/lib) 120 | if(NOT GLEW_LIBRARY) 121 | message(FATAL_ERROR "GLEW library not found") 122 | endif() 123 | 124 | # Find Qt5 and related files 125 | set(CMAKE_AUTOMOC ON) 126 | set(CMAKE_AUTOUIC ON) 127 | set(CMAKE_AUTORCC ON) 128 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 129 | 130 | find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets OpenGL Network PrintSupport) 131 | add_definitions(-DGL_SILENCE_DEPRECATION) 132 | 133 | # Generate Qt files (Qt5 handles most automatically with AUTOMOC/AUTOUIC/AUTORCC) 134 | qt5_wrap_ui(UI_FILES ${FORMS}) 135 | source_group("Generated" FILES ${UI_FILES}) 136 | 137 | # Set up paths and start building 138 | include_directories(${Boost_INCLUDE_DIR} ${OPENGL_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) 139 | add_executable(${PROJECT_NAME} ${SOURCES} ${UI_FILES} ${RESOURCES}) 140 | target_link_libraries(${PROJECT_NAME} 141 | Qt5::Core 142 | Qt5::Gui 143 | Qt5::Widgets 144 | Qt5::OpenGL 145 | Qt5::Network 146 | Qt5::PrintSupport 147 | ${Boost_LIBRARIES} 148 | ${OPENGL_LIBRARIES} 149 | ${GLEW_LIBRARY}) 150 | -------------------------------------------------------------------------------- /src/TaxiVis/layers/TripLocation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "TripLocation.hpp" 3 | #include "QMapTileWidget.hpp" 4 | #include "geographicalviewwidget.h" 5 | #include "global.h" 6 | #include 7 | #include 8 | 9 | // Qt's OpenGL headers undef GLEW macros, so we need to redefine them 10 | #ifndef glBindBuffer 11 | #define glBindBuffer __glewBindBuffer 12 | #endif 13 | 14 | TripLocation::TripLocation(GeographicalViewWidget *gw) : 15 | dataReady(false), 16 | bufferDirty(false), 17 | colorPickup(26, 77, 128, 204), 18 | colorDropoff(255, 51, 26, 204), 19 | geoWidget(gw) 20 | { 21 | } 22 | 23 | TripLocation::~TripLocation() 24 | { 25 | } 26 | 27 | void TripLocation::setEnabled(bool r) 28 | { 29 | if (this->enabled!=r) { 30 | this->enabled = r; 31 | if (this->enabled && !this->dataReady) 32 | this->buildLocations(); 33 | } 34 | } 35 | 36 | QColor TripLocation::pickupColor() 37 | { 38 | return this->colorPickup; 39 | } 40 | 41 | void TripLocation::setPickupColor(QColor color) 42 | { 43 | this->colorPickup = color; 44 | } 45 | 46 | QColor TripLocation::dropoffColor() 47 | { 48 | return this->colorDropoff; 49 | } 50 | 51 | void TripLocation::setDropoffColor(QColor color) 52 | { 53 | this->colorDropoff = color; 54 | } 55 | 56 | void TripLocation::render(QPainter *painter) 57 | { 58 | if (this->enabled && this->dataReady) { 59 | this->useGLPainting(painter); 60 | this->renderGL(); 61 | } 62 | } 63 | 64 | void TripLocation::updateData() 65 | { 66 | this->dataReady = false; 67 | if (this->enabled) 68 | this->buildLocations(); 69 | } 70 | 71 | void TripLocation::initGL() 72 | { 73 | glewInit(); 74 | this->glBuffer.generate(); 75 | const QOpenGLContext *context = QOpenGLContext::currentContext(); 76 | if (context) { 77 | this->shader = PQOpenGLShaderProgram(new QOpenGLShaderProgram()); 78 | this->shader->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Resources/shaders/location.120.vert"); 79 | this->shader->link(); 80 | } 81 | } 82 | 83 | void TripLocation::buildLocations() 84 | { 85 | KdTrip::TripSet::iterator it; 86 | KdTrip::TripSet *selectedTrips = this->geoWidget->getSelectedTrips(); 87 | this->vertices.clear(); 88 | this->vertices.resize(2*2*selectedTrips->size()); 89 | float *pickup = &this->vertices[0]; 90 | float *dropoff = pickup + 2*selectedTrips->size(); 91 | for (it=selectedTrips->begin(); it!=selectedTrips->end(); it++, pickup+=2, dropoff+=2) { 92 | const KdTrip::Trip *trip = *it; 93 | pickup[0] = trip->pickup_lat; 94 | pickup[1] = trip->pickup_long; 95 | dropoff[0] = trip->dropoff_lat; 96 | dropoff[1] = trip->dropoff_long; 97 | } 98 | this->bufferDirty = true; 99 | this->dataReady = true; 100 | } 101 | 102 | void TripLocation::renderGL() 103 | { 104 | if (this->bufferDirty) { 105 | this->glBuffer.setData(GL_ARRAY_BUFFER, this->vertices.size()*sizeof(float), &this->vertices[0], GL_DYNAMIC_DRAW); 106 | this->bufferDirty = false; 107 | } 108 | 109 | this->shader->bind(); 110 | 111 | QSizeF size = this->geoWidget->mapView()->size(); 112 | this->shader->setUniformValue("zoom", (float)this->geoWidget->mapView()->zoomLevel()); 113 | this->shader->setUniformValue("center", this->geoWidget->mapView()->center()); 114 | this->shader->setUniformValue("size", QVector2D(size.width(), size.height())); 115 | 116 | glEnable(GL_POINT_SMOOTH); 117 | 118 | glEnable(GL_BLEND); 119 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 120 | glEnableClientState(GL_VERTEX_ARRAY); 121 | 122 | glBindBuffer(GL_ARRAY_BUFFER, this->glBuffer.buffer); 123 | glVertexPointer(2, GL_FLOAT, 0, 0); 124 | 125 | float pointSize = 10.0*std::min(2.0, std::max(0.4, exp2(this->geoWidget->mapView()->zoomLevel()-15.0))); 126 | glPointSize(pointSize); 127 | 128 | glColor4f(this->colorPickup.redF(), 129 | this->colorPickup.greenF(), 130 | this->colorPickup.blueF(), 131 | this->colorPickup.alphaF()); 132 | glDrawArrays(GL_POINTS, 0, this->vertices.size()/4); 133 | 134 | glColor4f(this->colorDropoff.redF(), 135 | this->colorDropoff.greenF(), 136 | this->colorDropoff.blueF(), 137 | this->colorDropoff.alphaF()); 138 | glDrawArrays(GL_POINTS, this->vertices.size()/4, this->vertices.size()/4); 139 | 140 | glDisableClientState(GL_VERTEX_ARRAY); 141 | glDisable(GL_BLEND); 142 | 143 | this->shader->release(); 144 | glBindBuffer(GL_ARRAY_BUFFER, 0); 145 | } 146 | -------------------------------------------------------------------------------- /src/TaxiVis/layers/TripAnimationToolBar.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | TripAnimationToolBar 4 | 5 | 6 | 7 | 0 8 | 0 9 | 330 10 | 33 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | Trip Animation ToolBar 21 | 22 | 23 | background: transparent; 24 | 25 | 26 | 27 | 0 28 | 29 | 30 | 0 31 | 32 | 33 | 0 34 | 35 | 36 | 10 37 | 38 | 39 | 0 40 | 41 | 42 | 43 | 44 | ... 45 | 46 | 47 | 48 | :/Resources/icons/config.png 49 | :/Resources/icons/config_on.png:/Resources/icons/config.png 50 | 51 | 52 | true 53 | 54 | 55 | 56 | 57 | 58 | 59 | false 60 | 61 | 62 | ... 63 | 64 | 65 | 66 | :/Resources/icons/time.png 67 | :/Resources/icons/time_on.png:/Resources/icons/time.png 68 | 69 | 70 | true 71 | 72 | 73 | 74 | 75 | 76 | 77 | ... 78 | 79 | 80 | 81 | :/Resources/icons/play.png 82 | :/Resources/icons/pause.png:/Resources/icons/play.png 83 | 84 | 85 | true 86 | 87 | 88 | 89 | 90 | 91 | 92 | ... 93 | 94 | 95 | 96 | :/Resources/icons/reset.png:/Resources/icons/reset.png 97 | 98 | 99 | 100 | 101 | 102 | 103 | Qt::Horizontal 104 | 105 | 106 | QSizePolicy::Fixed 107 | 108 | 109 | 110 | 20 111 | 20 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | Qt::Horizontal 120 | 121 | 122 | 123 | 124 | 125 | 126 | Qt::Horizontal 127 | 128 | 129 | 130 | 0 131 | 20 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /src/TaxiVis/layers/GridMap.hpp: -------------------------------------------------------------------------------- 1 | #ifndef GRID_MAP_HPP 2 | #define GRID_MAP_HPP 3 | #include "RenderingLayer.hpp" 4 | #include "KdTrip.hpp" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | class ColorScale; 13 | class GeographicalViewWidget; 14 | class Grid; 15 | class GridCell; 16 | class QGraphicsItem; 17 | 18 | class GridMap : public QObject, public RenderingLayer 19 | { 20 | Q_OBJECT 21 | public: 22 | GridMap(GeographicalViewWidget *mw); 23 | virtual ~GridMap(); 24 | void loadGrid(QString gridFile); 25 | 26 | QColor borderColor(); 27 | void setBorderColor(QColor c); 28 | QColor fillColor(); 29 | void setFillColor(QColor c); 30 | 31 | void setColorScale(ColorScale *scale); 32 | ColorScale *getColorScale(); 33 | 34 | 35 | GridCell *highlightedCell(); 36 | void toggleHightlightedCellVisual(); 37 | 38 | QVector2D getCellValueRange(); 39 | 40 | virtual void setEnabled(bool r); 41 | virtual void initGL(); 42 | virtual void render(QPainter *painter); 43 | 44 | public slots: 45 | void updateData(); 46 | void viewChanged(QPointF,int); 47 | void doneUpdating(); 48 | 49 | protected: 50 | void buildCells(); 51 | void renderGL(); 52 | void renderLabel(QPainter *painter); 53 | void computeVisualData(); 54 | void updateCellVisualGeometry(GridCell *cell); 55 | 56 | virtual void renderPicking(); 57 | virtual void aggregateBegin() {} 58 | virtual void aggregateUpdate(int, const KdTrip::Trip *) {} 59 | virtual void aggregateEnd() {} 60 | virtual void aggregateOutput(GridCell &) {} 61 | virtual void updateCellVisualContents(GridCell *); 62 | virtual QGraphicsItem *createCellVisual(GridCell *); 63 | 64 | Grid *grid; 65 | QVector2D cellValueRange; 66 | 67 | bool dataReady; 68 | bool bufferDirty; 69 | bool visualDirty; 70 | 71 | GLBuffer buffer[3]; 72 | std::vector vertices; 73 | std::vector indices; 74 | std::vector triangles; 75 | 76 | PQOpenGLShaderProgram shader; 77 | PQOpenGLFramebufferObject fbo; 78 | 79 | QFont labelFont; 80 | QFontMetrics labelMetrics; 81 | 82 | QColor colorBorder; 83 | QColor colorFill; 84 | ColorScale *colorScale; 85 | 86 | int highlightId; 87 | 88 | typedef std::set CellSet; 89 | CellSet visualCells; 90 | 91 | GeographicalViewWidget *geoWidget; 92 | }; 93 | 94 | struct GridCell 95 | { 96 | GridCell(): visual(NULL) {} 97 | QString name; 98 | QList geometry; 99 | QRectF boundingRect; 100 | 101 | int id; 102 | int strokeIndices[2]; 103 | int fillIndices[2]; 104 | 105 | float value; 106 | QString label; 107 | QGraphicsItem *visual; 108 | 109 | KdTrip::TripSet trips; 110 | 111 | bool contains(const QPointF&p) const 112 | { 113 | if (!this->boundingRect.contains(p)) 114 | return false; 115 | for (int i=0; igeometry.size(); i++) 116 | if (this->geometry[i].containsPoint(p, Qt::OddEvenFill)) 117 | return true; 118 | return false; 119 | } 120 | }; 121 | 122 | class NumTripsGridMap : public GridMap 123 | { 124 | public: 125 | NumTripsGridMap(GeographicalViewWidget *gw); 126 | 127 | protected: 128 | std::vector counts; 129 | 130 | void aggregateBegin(); 131 | void aggregateUpdate(int, const KdTrip::Trip *); 132 | void aggregateEnd(); 133 | void aggregateOutput(GridCell &); 134 | }; 135 | 136 | class FarePerMileGridMap : public GridMap 137 | { 138 | public: 139 | FarePerMileGridMap(GeographicalViewWidget *gw); 140 | 141 | protected: 142 | std::vector counts; 143 | std::vector fares; 144 | 145 | void aggregateBegin(); 146 | void aggregateUpdate(int, const KdTrip::Trip *); 147 | void aggregateEnd(); 148 | void aggregateOutput(GridCell &); 149 | }; 150 | 151 | class PickupDropoffGridMap : public GridMap 152 | { 153 | public: 154 | PickupDropoffGridMap(GeographicalViewWidget *gw); 155 | 156 | protected: 157 | std::vector counts; 158 | std::vector< std::vector > ratios; 159 | 160 | void renderPicking(); 161 | void aggregateBegin(); 162 | void aggregateUpdate(int, const KdTrip::Trip *); 163 | void aggregateEnd(); 164 | void aggregateOutput(GridCell &); 165 | }; 166 | 167 | #endif 168 | -------------------------------------------------------------------------------- /src/TaxiVis/coordinator.cpp: -------------------------------------------------------------------------------- 1 | #include "coordinator.h" 2 | #include "viewwidget.h" 3 | #include "QMapWidget.hpp" 4 | #include "geographicalviewwidget.h" 5 | #include "temporalseriesplotwidget.h" 6 | #include "util/colorbar.h" 7 | #include "histogramwidget.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | Coordinator* Coordinator::_instance = 0; 14 | 15 | Coordinator::Coordinator(QObject *parent) : 16 | QObject(parent), enabled(true) 17 | { 18 | } 19 | 20 | void Coordinator::addView(ViewWidget *view) 21 | { 22 | _linkedViews.insert(view); 23 | _linkedPlots.insert(view->timeSeriesWidget()); 24 | _linkedHists.insert(view->histogramWidget()); 25 | this->addMapWidget((GeographicalViewWidget*)view->mapWidget()); 26 | setSeriesAttribute(view->timeSeriesWidget()->plotAttribute()); 27 | setHistsAttribute(view->histogramWidget()->plotAttribute()); 28 | } 29 | 30 | void Coordinator::addMapWidget(GeographicalViewWidget *widget) 31 | { 32 | _linkedMapViews.insert(widget->mapView()); 33 | _linkedMapWidgets.insert(widget); 34 | } 35 | 36 | void Coordinator::removeView(ViewWidget *view) 37 | { 38 | _linkedViews.remove(view); 39 | _linkedPlots.remove(view->timeSeriesWidget()); 40 | _linkedHists.remove(view->histogramWidget()); 41 | _linkedMapViews.remove(view->mapWidget()->mapView()); 42 | _linkedMapWidgets.remove((GeographicalViewWidget*)view->mapWidget()); 43 | 44 | view->timeSeriesWidget()->recomputePlots(); 45 | view->histogramWidget()->recomputePlots(); 46 | } 47 | 48 | bool Coordinator::containsView(ViewWidget *view) 49 | { 50 | return this->enabled && _linkedViews.contains(view); 51 | } 52 | 53 | bool Coordinator::containsTimeSeries(TemporalSeriesPlotWidget *plot) 54 | { 55 | return this->enabled && _linkedPlots.contains(plot); 56 | } 57 | 58 | bool Coordinator::containsMapView(QMapTileWidget *mw) 59 | { 60 | return this->enabled && _linkedMapViews.contains(mw); 61 | } 62 | 63 | bool Coordinator::containsHist(HistogramWidget *plot) 64 | { 65 | return this->enabled && _linkedHists.contains(plot); 66 | } 67 | 68 | void Coordinator::notifyAll() 69 | { 70 | // create lines using attribute 71 | foreach (TemporalSeriesPlotWidget *plot, _linkedPlots) { 72 | plot->setPlotAttribute(_seriesAttribute); 73 | plot->updatePlots(); 74 | } 75 | 76 | // compute max and min 77 | _yMin = 1000000000.f; 78 | _yMax = -1000000000.f; 79 | foreach (TemporalSeriesPlotWidget *plot, _linkedPlots) { 80 | _yMin = std::min(_yMin, plot->yMin()); 81 | _yMax = std::max(_yMax, plot->yMax()); 82 | } 83 | 84 | // update range in plots 85 | foreach (TemporalSeriesPlotWidget *plot, _linkedPlots) { 86 | plot->updateYRange(_yMin, _yMax); 87 | } 88 | 89 | // compute scalar max and min 90 | QVector2D range(1000000000., -1000000000.); 91 | foreach (ViewWidget *view, _linkedViews) { 92 | GeographicalViewWidget *gw = (GeographicalViewWidget*)view->mapWidget(); 93 | QVector2D r = gw->getScalarRange(); 94 | range.setX(std::min(range.x(), r.x())); 95 | range.setY(std::max(range.y(), r.y())); 96 | } 97 | foreach (ViewWidget *view, _linkedViews) { 98 | GeographicalViewWidget *gw = (GeographicalViewWidget*)view->mapWidget(); 99 | gw->getColorBar()->setRealMinMax(range.x(), range.y()); 100 | gw->repaintContents(); 101 | } 102 | 103 | // HISTOGRAMS 104 | foreach (HistogramWidget *plot, _linkedHists) { 105 | plot->setPlotAttribute(_histsAttribute); 106 | plot->updatePlots(); 107 | } 108 | 109 | // compute max and min for Histograms 110 | _yMin = 1000000000.f; 111 | _yMax = -1000000000.f; 112 | foreach (HistogramWidget *plot, _linkedHists) { 113 | _yMin = std::min(_yMin, plot->yMin()); 114 | _yMax = std::max(_yMax, plot->yMax()); 115 | } 116 | // update range in plots 117 | foreach (HistogramWidget *plot, _linkedHists) { 118 | plot->updateYRange(_yMin, _yMax); 119 | } 120 | 121 | } 122 | 123 | void Coordinator::notifyCameraChangeAll() 124 | { 125 | } 126 | 127 | void Coordinator::stepBackward(int mins){ 128 | 129 | } 130 | 131 | void Coordinator::stepForward(int mins){ 132 | 133 | } 134 | 135 | Coordinator *Coordinator::instance() 136 | { 137 | static QMutex mutex; 138 | if (!_instance) { 139 | mutex.lock(); 140 | if (!_instance) 141 | _instance = new Coordinator; 142 | mutex.unlock(); 143 | } 144 | return _instance; 145 | } 146 | 147 | bool Coordinator::isEnabled() 148 | { 149 | return this->enabled; 150 | } 151 | 152 | void Coordinator::setEnabled(bool b) 153 | { 154 | this->enabled = b; 155 | } 156 | -------------------------------------------------------------------------------- /src/TaxiVis/timeselectionwidget.cpp: -------------------------------------------------------------------------------- 1 | #include "timeselectionwidget.h" 2 | #include "ui_timeselectionwidget.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | TimeSelectionWidget::TimeSelectionWidget(QWidget *parent) : 12 | QWidget(parent), 13 | ui(new Ui::TimeSelectionWidget) 14 | { 15 | ui->setupUi(this); 16 | 17 | // 18 | uint x = 9668; 19 | ui->stepBackButton->setText(QString::fromUcs4(&x,1)); 20 | 21 | x = 9658; 22 | ui->stepForwardButton->setText(QString::fromUcs4(&x,1)); 23 | 24 | // 25 | connect(ui->queryButton,SIGNAL(clicked()),this,SLOT(timeDialogsChanged())); 26 | // 27 | connect(ui->exploreButton,SIGNAL(clicked()),this,SLOT(exploreTime())); 28 | 29 | } 30 | 31 | TimeSelectionWidget::~TimeSelectionWidget() 32 | { 33 | delete ui; 34 | } 35 | 36 | int TimeSelectionWidget::getStepSize(){ 37 | 38 | int stepSizeInMinutes = -1; 39 | QString selectedText = ui->comboBox_2->currentText(); 40 | 41 | if(!selectedText.compare(QString::fromLatin1("15 min"))){ 42 | stepSizeInMinutes = 15; 43 | } 44 | else if(!selectedText.compare(QString::fromLatin1("30 min"))){ 45 | stepSizeInMinutes = 30; 46 | } 47 | else if(!selectedText.compare(QString::fromLatin1("1 hour"))){ 48 | stepSizeInMinutes = 60; 49 | } 50 | else if(!selectedText.compare(QString::fromLatin1("1 day"))){ 51 | stepSizeInMinutes = 24*60; 52 | } 53 | else if(!selectedText.compare(QString::fromLatin1("1 week"))){ 54 | stepSizeInMinutes = 24*60*7; 55 | } 56 | 57 | assert(stepSizeInMinutes != -1);//make sure that one was selected 58 | 59 | return stepSizeInMinutes; 60 | } 61 | 62 | QDateTime TimeSelectionWidget::getStartTime(){ 63 | return ui->startTime->dateTime(); 64 | } 65 | 66 | QDateTime TimeSelectionWidget::getEndTime(){ 67 | return ui->endTime->dateTime(); 68 | } 69 | 70 | void TimeSelectionWidget::setTimes(QDateTime start, QDateTime end){ 71 | ui->startTime->setDateTime(start); 72 | ui->endTime->setDateTime(end); 73 | } 74 | 75 | void TimeSelectionWidget::stepBack(){ 76 | int stepSize = getStepSize(); 77 | 78 | QDateTime startDate = ui->startTime->dateTime(); 79 | startDate = startDate.addSecs(-stepSize*60); 80 | ui->startTime->setDateTime(startDate); 81 | QDateTime endDate = ui->endTime->dateTime(); 82 | endDate = endDate.addSecs(-stepSize*60); 83 | ui->endTime->setDateTime(endDate); 84 | 85 | timeDialogsChanged(); 86 | } 87 | 88 | void TimeSelectionWidget::stepForward(){ 89 | int stepSize = getStepSize(); 90 | 91 | QDateTime startDate = ui->startTime->dateTime(); 92 | startDate = startDate.addSecs(stepSize*60); 93 | ui->startTime->setDateTime(startDate); 94 | QDateTime endDate = ui->endTime->dateTime(); 95 | endDate = endDate.addSecs(stepSize*60); 96 | ui->endTime->setDateTime(endDate); 97 | 98 | timeDialogsChanged(); 99 | } 100 | 101 | void TimeSelectionWidget::timeDialogsChanged(){ 102 | if (this->ui->tabWidget->currentWidget()==this->ui->regularTimeWidget) { 103 | if(ui->startTime->dateTime() > ui->endTime->dateTime()){ 104 | QMessageBox::critical(this, QString::fromLatin1("Error"),QString::fromLatin1("Start time should be smaller than End Time!")); 105 | } 106 | else{ 107 | //qDebug() << "timeDialogsChanged " << getStartTime() << "; " << getEndTime(); 108 | emit timeUpdated(getStartTime(),getEndTime()); 109 | } 110 | } 111 | else if (this->ui->tabWidget->currentWidget()==this->ui->recurrentTimeWidget) { 112 | emit recurrentTimeUpdated(this->ui->recurrentTimeWidget); 113 | } 114 | } 115 | 116 | void TimeSelectionWidget::exploreTime() 117 | { 118 | if (this->ui->tabWidget->currentWidget()==this->ui->regularTimeWidget) { 119 | bool ok; 120 | int defaultValue[] = {4, 2, 2, 7, 4}; 121 | int steps = QInputDialog::getInt(this, "Parameter Exploration", 122 | QString("Specify the number of '%1' steps").arg(this->ui->comboBox_2->currentText()), 123 | defaultValue[this->ui->comboBox_2->currentIndex()], 2, 12, 1, &ok); 124 | if (ok) { 125 | uint stepSizes[] = {15, 30, 60, 24*60, 7*24*60}; 126 | uint delta = stepSizes[this->ui->comboBox_2->currentIndex()]*60; 127 | DateTimeList timeRanges; 128 | QDateTime start = this->getStartTime(); 129 | QDateTime end = this->getEndTime(); 130 | for (int i=0; iui->tabWidget->currentWidget()==this->ui->recurrentTimeWidget) { 136 | emit exploreInTime(this->ui->recurrentTimeWidget->getSelectedRanges()); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/preprocess/csv2Binary.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../TaxiVis/KdTrip.hpp" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | int main(int argc, char** argv){ 15 | if(argc != 3){ 16 | cout << "usage: ./csv2Binary " << endl; 17 | return -1; 18 | } 19 | 20 | // 21 | QString inputFilename = argv[1]; 22 | QString outputFilename = argv[2]; 23 | QFile file(inputFilename); 24 | 25 | if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { 26 | cout << "Could not open file: " << inputFilename.toStdString() << endl; 27 | return -1; 28 | } 29 | 30 | //ignore header 31 | QTextStream textStream(&file); 32 | QString header = textStream.readLine(); 33 | #ifdef DEBUG 34 | qDebug() << "Header: " << header; 35 | qDebug() << " Num Fields " << header.split(",").size(); 36 | #endif 37 | 38 | // 39 | QFile outputFile(outputFilename); 40 | if (!outputFile.open(QIODevice::WriteOnly)) { 41 | cout << "Could not write file: " << outputFilename.toStdString() << endl; 42 | return -1; 43 | } 44 | 45 | // 46 | QMap idsSoFar; 47 | QMap paymentsSoFar; 48 | 49 | int count = 1; 50 | 51 | while(!textStream.atEnd()){ 52 | QString line; 53 | QStringList tokens; 54 | 55 | if(count % 10000 == 0){ 56 | cout << "Processed " << count << " trips" << endl; 57 | } 58 | 59 | // 60 | line = textStream.readLine(); 61 | tokens = line.split(','); 62 | 63 | // 64 | KdTrip::Trip myTrip = {0}; 65 | QDateTime pickupDateTime = QDateTime::fromString(tokens[0],"yyyy-MM-dd HH:mm:ss"); 66 | QDateTime dropoffDateTime = QDateTime::fromString(tokens[1],"yyyy-MM-dd HH:mm:ss"); 67 | 68 | 69 | myTrip.pickup_time = pickupDateTime.toMSecsSinceEpoch()/1000;//KdTrip::Query::createTime(2011,5,1,8,1,55); 70 | myTrip.dropoff_time = dropoffDateTime.toMSecsSinceEpoch()/1000;//KdTrip::Query::createTime(2011,5,1,9,0,0); 71 | 72 | // 73 | myTrip.pickup_long = tokens[2].toFloat(); 74 | myTrip.pickup_lat = tokens[3].toFloat(); 75 | myTrip.dropoff_long = tokens[4].toFloat(); 76 | myTrip.dropoff_lat = tokens[5].toFloat(); 77 | 78 | // 79 | QString strID = tokens[6]; 80 | uint16_t idTaxi = 0; 81 | if(idsSoFar.count(strID) > 0){ 82 | idTaxi = idsSoFar[strID]; 83 | } 84 | else{ 85 | idTaxi = idsSoFar.size(); 86 | idsSoFar[strID] = idTaxi; 87 | } 88 | 89 | // 90 | QString strPayment = tokens[13]; 91 | uint8_t paymentType = 0; 92 | if(paymentsSoFar.count(strPayment) > 0){ 93 | paymentType = paymentsSoFar[strPayment]; 94 | } 95 | else{ 96 | paymentType = paymentsSoFar.size(); 97 | paymentsSoFar[strPayment] = paymentType; 98 | } 99 | 100 | // 101 | myTrip.id_taxi = idTaxi; 102 | myTrip.distance = (uint16_t)(tokens[7].toFloat() * 100); 103 | myTrip.fare_amount = (uint16_t)(tokens[8].toFloat() * 100); 104 | myTrip.surcharge = (uint16_t)(tokens[9].toFloat() * 100); 105 | myTrip.mta_tax = (uint16_t)(tokens[10].toFloat() * 100); 106 | myTrip.tip_amount = (uint16_t)(tokens[11].toFloat() * 100); 107 | myTrip.tolls_amount = (uint16_t)(tokens[12].toFloat() * 100); 108 | myTrip.payment_type = paymentType; 109 | myTrip.passengers = tokens[14].toUInt(); 110 | // 111 | myTrip.field1 = tokens[15].toUInt(); 112 | myTrip.field2 = tokens[16].toUInt(); 113 | myTrip.field3 = tokens[17].toUInt(); 114 | myTrip.field4 = tokens[18].toUInt(); 115 | 116 | // 117 | #ifdef DEBUG 118 | qDebug() << "Line:" << line; 119 | cout << " Taxi ID " << myTrip.id_taxi << endl; 120 | cout << " pickup_long " << myTrip.pickup_long << endl; 121 | cout << " pickup_lat " << myTrip.pickup_lat << endl; 122 | cout << " dropoff_long " << myTrip.dropoff_long << endl; 123 | cout << " dropoff_lat " << myTrip.pickup_lat << endl; 124 | cout << " fare " << myTrip.fare_amount << endl; 125 | cout << " distance " << myTrip.distance << endl; 126 | cout << " field 1 " << myTrip.field1 << endl; 127 | #endif 128 | 129 | // 130 | outputFile.write((char*)&myTrip,sizeof(KdTrip::Trip)); 131 | 132 | // 133 | ++count; 134 | } 135 | outputFile.close(); 136 | 137 | cout << "Wrote " << count << " trips" << endl; 138 | cout << " Size of trip " << sizeof(KdTrip::Trip) << endl; 139 | cout << " Total Size " << count * sizeof(KdTrip::Trip) << endl; 140 | 141 | return 0; 142 | } 143 | -------------------------------------------------------------------------------- /src/TaxiVis/HistogramDialog.cpp: -------------------------------------------------------------------------------- 1 | #include "HistogramDialog.hpp" 2 | #include "ui_HistogramDialog.h" 3 | #include "global.h" 4 | 5 | HistogramDialog::HistogramDialog(GeographicalViewWidget *geo, int numBins) 6 | : QDialog(geo), 7 | ui(new Ui::HistogramDialog), 8 | geoWidget(geo) 9 | { 10 | this->ui->setupUi(this); 11 | this->connect(this, SIGNAL(finished(int)), this, SLOT(onFinished(int))); 12 | 13 | this->trips = *this->geoWidget->getSelectedTrips(); 14 | QDateTime startTime = this->geoWidget->getSelectedStartTime(); 15 | QDateTime endTime = this->geoWidget->getSelectedEndTime(); 16 | SelectionGraph *selectionGraph = this->geoWidget->getSelectionGraph(); 17 | QGridLayout *layout = this->ui->gridLayout; 18 | 19 | //add extra widgets to deal with the extra fields 20 | Global* global = Global::getInstance(); 21 | int numExtraFields = global->numExtraFields(); 22 | int numCols = layout->columnCount(); 23 | int currentIndex = 0; 24 | for (int i=0; icount(); i++) { 25 | HistogramWidget *widget = dynamic_cast(layout->itemAt(i)->widget()); 26 | if (widget) { 27 | ++currentIndex; 28 | } 29 | } 30 | 31 | // 32 | for(int i = 0 ; i < numExtraFields ; ++i){ 33 | ExtraField field = global->getExtraField(i); 34 | if(field.active){ 35 | HistogramWidget *widget = new HistogramWidget(this); 36 | int col = currentIndex % numCols; 37 | int row = currentIndex / numCols; 38 | 39 | layout->addWidget(widget,row,col,1,1); 40 | ++currentIndex; 41 | } 42 | } 43 | 44 | // 45 | for (int i=0; icount(); i++) { 46 | HistogramWidget *widget = dynamic_cast(layout->itemAt(i)->widget()); 47 | if (widget) { 48 | QObjectList children = widget->children(); 49 | for (int j=0; j(children[j])) { 51 | ExtendedHistogram *plot = dynamic_cast(w); 52 | if (!plot) 53 | w->hide(); 54 | else 55 | this->plots.push_back(plot); 56 | } 57 | widget->setSelectionGraph(selectionGraph); 58 | widget->setSelectedTripsRepository(&this->trips); 59 | widget->setPlotAttribute((HistogramWidget::PlotAttribute)i); 60 | widget->setNumberOfBins(numBins); 61 | widget->recomputePlots(); 62 | } 63 | } 64 | for (int i=0; iplots.count(); i++) { 65 | this->connect(this->plots[i]->rangeDragAxis(Qt::Horizontal), 66 | SIGNAL(rangeChanged(const QCPRange&)), 67 | this, SLOT(xAxisRangeChanged(const QCPRange&))); 68 | this->connect(this->plots[i], 69 | SIGNAL(updateSelection(QList)), 70 | this, SLOT(updateSelection(QList))); 71 | } 72 | } 73 | 74 | HistogramDialog::~HistogramDialog() 75 | { 76 | delete this->ui; 77 | } 78 | 79 | void HistogramDialog::xAxisRangeChanged(const QCPRange &newRange) 80 | { 81 | for (int i=0; iplots.count(); i++) 82 | this->disconnect(this->plots[i]->rangeDragAxis(Qt::Horizontal), 83 | SIGNAL(rangeChanged(const QCPRange&)), 84 | this, SLOT(xAxisRangeChanged(const QCPRange&))); 85 | for (int i=0; iplots.count(); i++) { 86 | this->plots[i]->rangeDragAxis(Qt::Horizontal)->setRange(newRange); 87 | this->plots[i]->replot(); 88 | } 89 | for (int i=0; iplots.count(); i++) { 90 | this->connect(this->plots[i]->rangeDragAxis(Qt::Horizontal), 91 | SIGNAL(rangeChanged(const QCPRange&)), 92 | this, SLOT(xAxisRangeChanged(const QCPRange&))); 93 | } 94 | } 95 | 96 | void HistogramDialog::updateSelection(QList) 97 | { 98 | int selectionCount = 0; 99 | for (int i=0; iplots.count(); i++) { 100 | selectionCount += this->plots.at(i)->getSelections().count(); 101 | } 102 | KdTrip::TripSet out = this->trips; 103 | QGridLayout *layout = this->ui->gridLayout; 104 | QStringList descList; 105 | for (int i=0; icount(); i++) { 106 | HistogramWidget *widget = dynamic_cast(layout->itemAt(i)->widget()); 107 | if (widget) { 108 | widget->joinSelectedTrips(&out); 109 | QString desc = widget->getAttributeDescription(); 110 | if (!desc.isEmpty()) 111 | descList << desc; 112 | } 113 | } 114 | this->geoWidget->getSelectedTrips()->swap(out); 115 | this->geoWidget->setQueryDescription(descList); 116 | this->geoWidget->emitDatasetUpdated(); 117 | this->geoWidget->repaintContents(); 118 | } 119 | 120 | KdTrip::TripSet * HistogramDialog::selectedTrips() 121 | { 122 | return &this->trips; 123 | } 124 | 125 | void HistogramDialog::onFinished(int result) 126 | { 127 | if (result==QDialog::Rejected) { 128 | this->geoWidget->getSelectedTrips()->swap(this->trips); 129 | this->geoWidget->setQueryDescription(QStringList()); 130 | this->geoWidget->emitDatasetUpdated(); 131 | this->geoWidget->repaintContents(); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/TaxiVis/histogramwidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | HistogramWidget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 808 10 | 313 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | 0 21 | 22 | 23 | 24 | 25 | Qt::Horizontal 26 | 27 | 28 | 29 | 40 30 | 20 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | Attribute: 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | Fare Amount 49 | 50 | 51 | 52 | 53 | Tip 54 | 55 | 56 | 57 | 58 | Distance 59 | 60 | 61 | 62 | 63 | Duration 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | Qt::Horizontal 72 | 73 | 74 | 75 | 40 76 | 20 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | Num Bins 85 | 86 | 87 | 88 | 89 | 90 | 91 | 1 92 | 93 | 94 | 10000 95 | 96 | 97 | 10 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | Qt::Horizontal 107 | 108 | 109 | 110 | 40 111 | 20 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | ExtendedHistogram 126 | QWidget 127 |
extendedhistogram.h
128 | 1 129 |
130 |
131 | 132 | 133 | 134 | attributeComboBox 135 | currentIndexChanged(QString) 136 | HistogramWidget 137 | changeHistAttribute(QString) 138 | 139 | 140 | 377 141 | 29 142 | 143 | 144 | 806 145 | 55 146 | 147 | 148 | 149 | 150 | numBinsSpinBox 151 | valueChanged(int) 152 | HistogramWidget 153 | setNumberOfBins(int) 154 | 155 | 156 | 572 157 | 24 158 | 159 | 160 | 804 161 | 109 162 | 163 | 164 | 165 | 166 | 167 | changeHistAttribute(QString) 168 | setNumberOfBins(int) 169 | 170 |
171 | -------------------------------------------------------------------------------- /src/TaxiVis/temporalseriesplotwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef PLOTWIDGET_H 2 | #define PLOTWIDGET_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "KdTrip.hpp" 9 | #include "Group.h" 10 | #include "SelectionGraph.h" 11 | 12 | namespace Ui { 13 | class PlotWidget; 14 | } 15 | 16 | class Coordinator; 17 | 18 | struct HourSlot { 19 | uint64_t startTime; 20 | uint64_t endTime; 21 | uint64_t num_trips; 22 | uint64_t num_taxis; 23 | float sum_distance; 24 | float sum_tips; 25 | float sum_fare_amount; 26 | float sum_tools_amount; 27 | float sum_duration; 28 | float sum_avg_speed; 29 | // 30 | float sum_field1; 31 | float sum_field2; 32 | float sum_field3; 33 | float sum_field4; 34 | HourSlot(uint64_t startTime, uint64_t endTime): 35 | startTime(startTime), 36 | endTime(endTime), 37 | num_trips(0), 38 | num_taxis(0), 39 | sum_distance(0), 40 | sum_tips(0), 41 | sum_fare_amount(0), 42 | sum_tools_amount(0), 43 | sum_duration(0), 44 | sum_avg_speed(0), 45 | sum_field1(0), 46 | sum_field2(0), 47 | sum_field3(0), 48 | sum_field4(0) 49 | {} 50 | void reset(uint64_t startTime, uint64_t endTime) 51 | { 52 | this->startTime = startTime; 53 | this->endTime = endTime; 54 | this->num_trips = 0; 55 | this->num_taxis = 0; 56 | this->sum_distance = 0; 57 | this->sum_tips = 0; 58 | this->sum_fare_amount = 0; 59 | this->sum_tools_amount = 0; 60 | this->sum_duration = 0; 61 | this->sum_avg_speed = 0; 62 | // 63 | this->sum_field1 = 0; 64 | this->sum_field2 = 0; 65 | this->sum_field3 = 0; 66 | this->sum_field4 = 0; 67 | } 68 | inline void update(const KdTrip::Trip *trip){ 69 | this->num_trips += 1; 70 | this->sum_distance += trip->distance; 71 | this->sum_fare_amount += trip->fare_amount; 72 | this->sum_tips += trip->tip_amount; 73 | this->sum_tools_amount += trip->tolls_amount/100.f; 74 | // 75 | this->sum_field1 += trip->field1; 76 | this->sum_field2 += trip->field2; 77 | this->sum_field3 += trip->field3; 78 | this->sum_field4 += trip->field4; 79 | // 80 | int32_t tripDuration = (trip->dropoff_time- trip->pickup_time); 81 | if(tripDuration > 0){ 82 | this->sum_duration += tripDuration; 83 | this->sum_avg_speed += (trip->distance/(1.0f*tripDuration)); 84 | } 85 | } 86 | }; 87 | 88 | class TemporalSeriesPlotWidget : public QWidget 89 | { 90 | Q_OBJECT 91 | public: 92 | enum PlotAttribute{ 93 | NUMBER_OF_TRIPS, FARE_AMOUNT, TIP_AMOUNT, TOTAL_AMOUNT, 94 | FARE_PER_TRIP, FARE_PER_MILE, TIP_PER_TRIP, TIP_PER_MILE, 95 | NUM_TAXIS,TOLL_AMOUNT,TOLL_PER_TRIP, DURATION_PER_TRIP, DISTANCE_PER_TRIP, AVG_SPEED_PER_TRIP, 96 | FIELD1,FIELD2,FIELD3,FIELD4 97 | }; 98 | 99 | public: 100 | explicit TemporalSeriesPlotWidget(QWidget *parent = 0); 101 | ~TemporalSeriesPlotWidget(); 102 | 103 | void setSelectedTripsRepository(KdTrip::TripSet *); 104 | 105 | float yMin() { return _yMin; } 106 | float yMax() { return _yMax; } 107 | PlotAttribute plotAttribute() {return _plotAttribute;} 108 | 109 | private: 110 | Ui::PlotWidget *ui; 111 | KdTrip::TripSet*selectedTrips; 112 | 113 | // 114 | SelectionGraph* selectionGraph; 115 | QDateTime startTime; 116 | QDateTime endTime; 117 | 118 | // 119 | Coordinator *coordinator; 120 | 121 | // 122 | std::map > groupPlots; 123 | PlotAttribute _plotAttribute; 124 | int numBins; 125 | float _yMin; 126 | float _yMax; 127 | 128 | 129 | void computePlots(); 130 | void setNumBins(int n); 131 | 132 | // 133 | bool tripSatisfiesEdge(const KdTrip::Trip *trip, SelectionGraphEdge* edge); 134 | bool tripSatisfiesConstraints(const KdTrip::Trip *trip, 135 | std::vector groupNodeConstraints, 136 | std::vector groupEdgeConstraints); 137 | 138 | public: 139 | void recomputePlots(); 140 | void updatePlots(); 141 | void setSelectionGraph(SelectionGraph*); 142 | void setDateTimes(QDateTime,QDateTime); 143 | void setPlotAttribute(TemporalSeriesPlotWidget::PlotAttribute pAttrib); 144 | void setNumberOfBins(int n); 145 | int getNumberOfBins(); 146 | void setCoordinator(Coordinator *c); 147 | 148 | public slots: 149 | void updateNumBins(); 150 | void updatePlotAttrib(QString); 151 | void updateYRange(float min, float max); 152 | void selectionChanged(QDateTime,QDateTime); 153 | private slots: 154 | void mousePress(); 155 | void mouseWheel(); 156 | signals: 157 | void timeIntervalChanged(QDateTime,QDateTime); 158 | }; 159 | 160 | #endif // PLOTWIDGET_H 161 | -------------------------------------------------------------------------------- /src/preprocess/radix.h: -------------------------------------------------------------------------------- 1 | #ifndef RADIX_H 2 | #define RADIX_H 3 | #include 4 | 5 | // ============================================================================ 6 | // TIMING 7 | // ============================================================================ 8 | #ifdef _WIN32 9 | #include 10 | #define WALLCLOCK() ((double)GetTickCount()*1e-3) 11 | 12 | #else 13 | 14 | #include 15 | inline double WALLCLOCK() { 16 | struct timeval tv; 17 | gettimeofday(&tv, NULL); 18 | return tv.tv_sec + tv.tv_usec*1e-6; 19 | } 20 | #endif 21 | 22 | // ============================================================================ 23 | // DATA MANIPULATION 24 | // ============================================================================ 25 | #define float2fintm(f) f ^ ((-(f >> 31)) | 0x80000000) 26 | #define fint2floatm(f) f ^ (((f >> 31) - 1) | 0x80000000) 27 | #define GETBYTE(a, b) ((a >> (b << 3)) & 0xFF) 28 | #define GETWORD(a, b) ((a >> (b << 4)) & 0xFFFF) 29 | #define SWAP(TYPE, __x, __y) { register TYPE __tmp(__x); __x = __y; __y = __tmp; } 30 | #define MAX(A, B) ((A)>(B)?(A):(B)) 31 | 32 | // ============================================================================ 33 | // IN-PLACE RADIX SORT 34 | // ============================================================================ 35 | #define MIN_FOR_RADIX 64 36 | #define USE_TEMPLATE 0 37 | 38 | inline void inplaceInsertionSort(uint32_t *a, int n) { 39 | register unsigned i, j; 40 | register uint32_t k; 41 | for (i=0; i!=n; i++, a[j]=k) 42 | for (j=i, k=a[j]; j && k0) { 84 | end += count[i]; 85 | for (j=bucket[i]; j0) { 96 | if (count[i] 106 | inline void inplaceRadixSortByte(uint32_t *a, int n) { 107 | unsigned i, j, end; 108 | unsigned count[256] = {}; 109 | 110 | for (i=0; i0) { 120 | end += count[i]; 121 | for (j=bucket[i]; j0) { 132 | if (count[i](a+end-count[i], count[i]); 136 | } 137 | } 138 | } 139 | } 140 | 141 | template<> 142 | inline void inplaceRadixSortByte<0>(uint32_t *a, int n) { 143 | unsigned i, j, k, end; 144 | unsigned count[256] = {}; 145 | 146 | for (i=0; i(a, n); 171 | } 172 | 173 | #endif 174 | -------------------------------------------------------------------------------- /src/preprocess/csv2Binary.jl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env julia 2 | 3 | using CSV 4 | using DataFrames 5 | using Dates 6 | 7 | # Trip struct matching C++ KdTrip::Trip (48 bytes total) 8 | # Must match exact layout in KdTrip.hpp 9 | struct Trip 10 | pickup_time::UInt32 # 4 bytes 11 | dropoff_time::UInt32 # 4 bytes 12 | pickup_long::Float32 # 4 bytes 13 | pickup_lat::Float32 # 4 bytes 14 | dropoff_long::Float32 # 4 bytes 15 | dropoff_lat::Float32 # 4 bytes 16 | field1::UInt32 # 4 bytes 17 | field2::UInt32 # 4 bytes 18 | field3::UInt32 # 4 bytes 19 | field4::UInt32 # 4 bytes 20 | id_taxi::UInt16 # 2 bytes 21 | distance::UInt16 # 2 bytes (in 0.01 miles) 22 | fare_amount::UInt16 # 2 bytes (in cents) 23 | surcharge::UInt16 # 2 bytes (in cents) 24 | mta_tax::UInt16 # 2 bytes (in cents) 25 | tip_amount::UInt16 # 2 bytes (in cents) 26 | tolls_amount::UInt16 # 2 bytes (in cents) 27 | payment_type::UInt8 # 1 byte 28 | passengers::UInt8 # 1 byte 29 | end 30 | 31 | function parse_datetime_to_unix(dt_str) 32 | # Parse "2012-01-06 21:51:00" format to Unix timestamp 33 | dt = DateTime(dt_str, "yyyy-mm-dd HH:MM:SS") 34 | return UInt32(round(datetime2unix(dt))) 35 | end 36 | 37 | function main() 38 | if length(ARGS) != 2 39 | println("Usage: julia csv2Binary.jl ") 40 | exit(1) 41 | end 42 | 43 | input_file = ARGS[1] 44 | output_file = ARGS[2] 45 | 46 | println("Loading CSV data from: $input_file") 47 | df = CSV.read(input_file, DataFrame, stripwhitespace=true) 48 | 49 | println("Loaded $(nrow(df)) trips") 50 | 51 | # Create mappings for taxi IDs and payment types 52 | taxi_id_map = Dict{String, UInt16}() 53 | payment_type_map = Dict{String, UInt8}() 54 | 55 | println("Converting to binary format...") 56 | open(output_file, "w") do io 57 | for (i, row) in enumerate(eachrow(df)) 58 | if i % 100000 == 0 59 | println(" Processed $i trips") 60 | end 61 | 62 | # Map taxi ID (medallion hash) to integer 63 | taxi_str = string(row.id_taxi) 64 | if !haskey(taxi_id_map, taxi_str) 65 | taxi_id_map[taxi_str] = UInt16(length(taxi_id_map)) 66 | end 67 | id_taxi = taxi_id_map[taxi_str] 68 | 69 | # Map payment type to integer 70 | payment_str = string(row.payment_type) 71 | if !haskey(payment_type_map, payment_str) 72 | payment_type_map[payment_str] = UInt8(length(payment_type_map)) 73 | end 74 | payment_type = payment_type_map[payment_str] 75 | 76 | # Create trip struct 77 | trip = Trip( 78 | parse_datetime_to_unix(row.pickup_time), 79 | parse_datetime_to_unix(row.dropoff_time), 80 | Float32(row.pickup_long), 81 | Float32(row.pickup_lat), 82 | Float32(row.dropoff_long), 83 | Float32(row.dropoff_lat), 84 | UInt32(row.field1), 85 | UInt32(row.field2), 86 | UInt32(row.field3), 87 | UInt32(row.field4), 88 | id_taxi, 89 | UInt16(round(row.distance * 100)), # Convert to 0.01 miles 90 | UInt16(round(row.fare_amount * 100)), # Convert to cents 91 | UInt16(round(row.surcharge * 100)), # Convert to cents 92 | UInt16(round(row.mta_tax * 100)), # Convert to cents 93 | UInt16(round(row.tip_amount * 100)), # Convert to cents 94 | UInt16(round(row.tolls_amount * 100)), # Convert to cents 95 | payment_type, 96 | UInt8(row.passengers) 97 | ) 98 | 99 | # Write binary struct field by field 100 | write(io, trip.pickup_time) 101 | write(io, trip.dropoff_time) 102 | write(io, trip.pickup_long) 103 | write(io, trip.pickup_lat) 104 | write(io, trip.dropoff_long) 105 | write(io, trip.dropoff_lat) 106 | write(io, trip.field1) 107 | write(io, trip.field2) 108 | write(io, trip.field3) 109 | write(io, trip.field4) 110 | write(io, trip.id_taxi) 111 | write(io, trip.distance) 112 | write(io, trip.fare_amount) 113 | write(io, trip.surcharge) 114 | write(io, trip.mta_tax) 115 | write(io, trip.tip_amount) 116 | write(io, trip.tolls_amount) 117 | write(io, trip.payment_type) 118 | write(io, trip.passengers) 119 | end 120 | end 121 | 122 | trip_count = nrow(df) 123 | trip_size = sizeof(Trip) 124 | total_size = trip_count * trip_size 125 | 126 | println("Wrote $trip_count trips") 127 | println(" Size of trip: $trip_size bytes") 128 | println(" Total size: $total_size bytes") 129 | println(" Unique taxis: $(length(taxi_id_map))") 130 | println(" Unique payment types: $(length(payment_type_map))") 131 | end 132 | 133 | main() 134 | -------------------------------------------------------------------------------- /doc/MAP_RESTORATION_PLAN.md: -------------------------------------------------------------------------------- 1 | # Map Restoration Plan 2 | 3 | ## Problem Statement 4 | 5 | TaxiVis requires a map widget for its core functionality, but the original implementation used QtWebKit (QGraphicsWebView), which was deprecated and removed from Qt 5.6+. The Qt5 migration disabled map functionality using `NO_WEBKIT` preprocessor guards. 6 | 7 | ## Current Architecture 8 | 9 | The map system has three layers: 10 | 11 | 1. **QMapWidget** (QGraphicsView) - Container widget 12 | - Sets up QGraphicsScene 13 | - Manages viewport with OpenGL rendering 14 | - Handles resize events 15 | 16 | 2. **QMapView** (QGraphicsWebView) - Web view showing Google Maps 17 | - Embeds in QGraphicsScene 18 | - Loads Google Maps via HTML/JavaScript 19 | - Handles pan/zoom interactions 20 | - Provides coordinate transformations (lat/lon ↔ screen coordinates) 21 | 22 | 3. **RenderingLayers** - OpenGL overlays on top of map 23 | - Trip points (blue = pickup, red = dropoff) 24 | - Heat maps 25 | - Neighborhood aggregations 26 | - Selection regions (polygons, arrows) 27 | 28 | **Key Design**: QGraphicsWebView allows embedding a web browser in a QGraphicsScene, which can then be overlaid with OpenGL-rendered content using QPainter in the `paint()` method. 29 | 30 | ## Migration Options Evaluated 31 | 32 | ### Option A: QtWebEngine (Qt5 Official Replacement) 33 | **Status**: ❌ **Rejected** 34 | 35 | **Why rejected**: 36 | - QtWebEngine has no QGraphicsWebView equivalent 37 | - Only provides QWebEngineView (standard QWidget) 38 | - Cannot be embedded in QGraphicsScene 39 | - Rendering happens in separate Chromium process 40 | - Would require complete architecture redesign 41 | - No direct QPainter integration 42 | 43 | **Effort**: 🔴 High (3-4 weeks) - Complete rewrite of widget hierarchy 44 | 45 | ### Option B: Custom Tile-Based Map 46 | **Status**: ⏸️ **Deferred** (fallback option) 47 | 48 | **Pros**: 49 | - No web engine dependency 50 | - Native Qt/OpenGL integration 51 | - Lighter weight 52 | - Better performance 53 | - Future-proof 54 | 55 | **Cons**: 56 | - Need to implement tile loading from OpenStreetMap 57 | - Need to implement pan/zoom logic 58 | - More upfront development 59 | 60 | **Effort**: 🟡 Medium (1-2 weeks) 61 | 62 | **Implementation outline**: 63 | 1. Replace QGraphicsWebView with custom QGraphicsWidget 64 | 2. Implement tile loading (HTTP requests to tile servers) 65 | 3. Implement tile caching and rendering 66 | 4. Implement pan/zoom transforms 67 | 5. Keep all existing RenderingLayers unchanged 68 | 69 | ### Option C: QtWebKit from 3rd Party Source 70 | **Status**: ✅ **Selected** (trying first) 71 | 72 | **Why selected**: 73 | - Minimal code changes required 74 | - QGraphicsWebView API remains available 75 | - Maintains current architecture intact 76 | - Quickest path to working map 77 | - Can fall back to Option B if issues arise 78 | 79 | **Cons**: 80 | - Not officially supported by Qt 81 | - Security concerns (outdated browser engine for 2011 data) 82 | - Dependency on 3rd party package 83 | 84 | **Effort**: 🟢 Low (1-2 days) 85 | 86 | ## Implementation Plan: Option C 87 | 88 | ### Step 1: Install QtWebKit 89 | ```bash 90 | brew install qt-webkit@5 91 | ``` 92 | 93 | ### Step 2: Update CMakeLists.txt 94 | - Remove `NO_WEBKIT` definition 95 | - Find and link Qt5WebKit and Qt5WebKitWidgets packages 96 | - Re-enable map-related source files 97 | 98 | ### Step 3: Update Source Files 99 | - Remove `#ifndef NO_WEBKIT` guards from: 100 | - mainwindow.cpp 101 | - coordinator.cpp 102 | - geographicalviewwidget.h/cpp 103 | - QMapWidget.cpp 104 | 105 | ### Step 4: Fix Build Issues 106 | - Resolve any API incompatibilities 107 | - Update deprecated Qt5 APIs if needed 108 | 109 | ### Step 5: Test 110 | - Verify map loads with Google Maps tiles 111 | - Test pan/zoom functionality 112 | - Test spatial query features (polygon selection, etc.) 113 | - Verify rendering layers work correctly 114 | 115 | ### Fallback Criteria 116 | 117 | Switch to **Option B** (custom tiles) if: 118 | - QtWebKit package is unavailable or incompatible 119 | - Build errors are too complex to resolve quickly (>1 day) 120 | - Runtime crashes or instability 121 | - Google Maps no longer works with old QtWebKit 122 | 123 | ## Current Status 124 | 125 | - **Date**: 2025-10-22 126 | - **Branch**: qt5-upgrade 127 | - **Checkpoint commit**: (to be created) 128 | - **Attempting**: Option C (QtWebKit from 3rd party) 129 | 130 | ## Files Modified for NO_WEBKIT Guards 131 | 132 | Core files that need guards removed: 133 | 134 | 1. `src/TaxiVis/mainwindow.cpp` - Map initialization on startup 135 | 2. `src/TaxiVis/coordinator.cpp` - ViewWidget management 136 | 3. `src/TaxiVis/geographicalviewwidget.h` - Inheritance from QMapWidget 137 | 4. `src/TaxiVis/QMapWidget.cpp` - WebKit settings 138 | 5. `src/TaxiVis/CMakeLists.txt` - Build configuration 139 | 140 | Disabled files (currently commented out in CMakeLists.txt): 141 | - QMapView.cpp 142 | - QMapWidget.cpp 143 | - viewwidget.cpp 144 | - geographicalviewwidget.cpp 145 | 146 | ## References 147 | 148 | - [QtWebKit 5.212 Documentation](https://github.com/qt/qtwebkit) 149 | - [OpenStreetMap Tile Servers](https://wiki.openstreetmap.org/wiki/Tile_servers) 150 | - [Leaflet.js](https://leafletjs.com/) - For Option B reference 151 | - UPGRADE_PLAN.md - Original Qt5 migration plan 152 | --------------------------------------------------------------------------------