Skip to content

Commit

Permalink
Day & night background coloring in forecast tab.
Browse files Browse the repository at this point in the history
  • Loading branch information
FelixdelasPozas committed Nov 14, 2023
1 parent 78aa9cd commit 2d47b7b
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 14 deletions.
2 changes: 1 addition & 1 deletion AboutDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#include <QDateTime>
#include <QApplication>

const QString AboutDialog::VERSION{"1.26.1"};
const QString AboutDialog::VERSION{"1.27.0"};
const QString COPYRIGHT{"Copyright (c) 2016-%1 Félix de las Pozas Álvarez"};

//-----------------------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ cmake_minimum_required (VERSION 3.0.0)

# Version Number
set (TRAYWEATHER_VERSION_MAJOR 1)
set (TRAYWEATHER_VERSION_MINOR 26)
set (TRAYWEATHER_VERSION_PATCH 1)
set (TRAYWEATHER_VERSION_MINOR 27)
set (TRAYWEATHER_VERSION_PATCH 0)

set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down
2 changes: 1 addition & 1 deletion ConfigurationDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1359,7 +1359,7 @@ QPixmap ConfigurationDialog::generateTemperatureIconPixmap(QFont &font)
QPixmap pixmap(384,384);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
font.setPixelSize(200);
font.setPixelSize(150);
painter.setFont(font);

QColor color;
Expand Down
39 changes: 39 additions & 0 deletions Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,14 @@
#include <QDir>

// C++
#define _USE_MATH_DEFINES
#include <functional>
#include <exception>
#include <memory>
#include <cmath>
#include <windows.h>
#include <iostream>
#include <ctime>

static const QString INI_FILENAME = QString("TrayWeather.ini");

Expand Down Expand Up @@ -1154,3 +1156,40 @@ QRect computeDrawnRect(const QImage &image)
const auto maxY = lastY-firstY;
return QRect(firstX, firstY, maxX, maxY);
}

//--------------------------------------------------------------------
std::pair<unsigned long long, unsigned long long> computeSunriseSunset(const ForecastData &data, const double longitude, const double latitude)
{
// convert to day of year
struct tm t;
unixTimeStampToDate(t, data.dt);

// From http://edwilliams.org/sunrise_sunset_algorithm.htm
const auto N1 = std::floor(275 * t.tm_mon / 9);
const auto N2 = std::floor((t.tm_mon + 9) / 12);
const auto N3 = (1 + std::floor((t.tm_year - 4 * std::floor(t.tm_year / 4) + 2) / 3));
const auto dayOfYear = N1 - (N2 * N3) + t.tm_mday - 30;

// From https://codepal.ai/code-generator/query/GDQrUujP/c-function-sunrise-sunset-time
// Calculate the solar declination
const double solarDeclination = 0.4093 * std::sin(2 * M_PI * (dayOfYear - 81) / 365);

// Calculate the hour angle
const double hourAngle = std::acos(-std::tan(latitude * M_PI / 180) * std::tan(solarDeclination));

// Calculate the sunrise and sunset times
const auto sunriseTime = 12 - (hourAngle * 180 / M_PI) / 15;
const auto sunsetTime = 12 + (hourAngle * 180 / M_PI) / 15;

t.tm_hour = static_cast<int>(sunriseTime);
t.tm_min = static_cast<int>((sunriseTime - t.tm_hour) * 60.0);
t.tm_sec = static_cast<int>((((sunriseTime - t.tm_hour) * 60.0) - t.tm_min) * 60.0);
const unsigned long long unixSunrise = std::mktime(&t);

t.tm_hour = static_cast<int>(sunsetTime);
t.tm_min = static_cast<int>((sunsetTime - t.tm_hour) * 60.0);
t.tm_sec = static_cast<int>((((sunsetTime - t.tm_hour) * 60.0) - t.tm_min) * 60.0);
const unsigned long long unixSunset = std::mktime(&t);

return std::make_pair(unixSunrise, unixSunset);
}
12 changes: 10 additions & 2 deletions Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ struct LanguageData
* \param[in] f Filename of the translation file without extension.
*
*/
LanguageData(const QString n, const QString i, const QString f, const QString a): name{n}, icon{i}, file{f}, author{a} {};
LanguageData(const QString n, const QString i, const QString f, const QString a): name(n), icon(i), file(f), author(a) {};
};

/** Translations
Expand Down Expand Up @@ -235,7 +235,7 @@ struct Configuration
, minimumValue {-10}
, maximumValue {45}
, update {Update::WEEKLY}
, lastCheck {QDateTime::currentDateTime()}
, lastCheck (QDateTime::currentDateTime())
, autostart {false}
, lastTab {0}
, lastLayer {"temperature"}
Expand Down Expand Up @@ -586,6 +586,14 @@ QPixmap createIconsSummary(const unsigned int theme, const int size, const QColo
*/
QRect computeDrawnRect(const QImage &image);

/** \brief Computes and returns the sunrise and sunset time in unix time for the given ForecastData date and coordinates.
* \param[in] data ForecastData struct.
* \param[in] longitude
* \param[in] latitude
*
*/
std::pair<unsigned long long, unsigned long long> computeSunriseSunset (const ForecastData &data, const double longitude, const double latitude);

/** \class CustomComboBox
* \brief ComboBox that uses rich text for selected item.
*
Expand Down
62 changes: 60 additions & 2 deletions WeatherDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ using namespace QtCharts;

//--------------------------------------------------------------------
WeatherDialog::WeatherDialog(QWidget* parent, Qt::WindowFlags flags)
: QDialog {parent, flags}
: QDialog (parent, flags)
, m_forecast {nullptr}
, m_config {nullptr}
, m_weatherTooltip {nullptr}
Expand Down Expand Up @@ -478,8 +478,15 @@ void WeatherDialog::setWeatherData(const ForecastData &current, const Forecast &
}
};

for(auto &entry: data)
QLinearGradient plotAreaGradient;
plotAreaGradient.setStart(QPointF(0, 0));
plotAreaGradient.setFinalStop(QPointF(1, 0));
plotAreaGradient.setCoordinateMode(QGradient::ObjectBoundingMode);

for(int i = 0; i < data.size(); ++i)
{
const auto &entry = data.at(i);

unixTimeStampToDate(t, entry.dt);
dtTime = QDateTime{QDate{t.tm_year + 1900, t.tm_mon + 1, t.tm_mday}, QTime{t.tm_hour, t.tm_min, t.tm_sec}};

Expand All @@ -501,8 +508,16 @@ void WeatherDialog::setWeatherData(const ForecastData &current, const Forecast &

snowMin = std::min(snowMin, value);
snowMax = std::max(snowMax, value);

const auto sunTimes = computeSunriseSunset(entry, m_config->longitude, m_config->latitude);
const auto entryDt = static_cast<unsigned long long>(entry.dt);
const bool isDay = entryDt > sunTimes.first && entryDt < sunTimes.second;
plotAreaGradient.setColorAt(static_cast<double>(i)/(data.size()-1), isDay ? Qt::white:Qt::lightGray);
}

forecastChart->setPlotAreaBackgroundBrush(plotAreaGradient);
forecastChart->setPlotAreaBackgroundVisible(true);

axisYTemp->setProperty("axisType", "temp");

// Bar series need to be added first so they don't hide the line series.
Expand Down Expand Up @@ -574,6 +589,8 @@ void WeatherDialog::setWeatherData(const ForecastData &current, const Forecast &

connect(axisX, SIGNAL(rangeChanged(QDateTime, QDateTime)),
this, SLOT(onAreaChanged()));
connect(axisX, SIGNAL(rangeChanged(QDateTime, QDateTime)),
this, SLOT(onForecastAreaChanged(QDateTime, QDateTime)));

if(oldChart)
{
Expand All @@ -582,6 +599,9 @@ void WeatherDialog::setWeatherData(const ForecastData &current, const Forecast &
{
disconnect(axis, SIGNAL(rangeChanged(QDateTime, QDateTime)),
this, SLOT(onAreaChanged()));
disconnect(axisX, SIGNAL(rangeChanged(QDateTime, QDateTime)),
this, SLOT(onForecastAreaChanged(QDateTime, QDateTime)));

}

delete oldChart;
Expand Down Expand Up @@ -1675,3 +1695,41 @@ void WeatherDialog::updateAxesRanges(QtCharts::QChart *chart)
axis->setVisible(timesUsed > 0);
}
}

//--------------------------------------------------------------------
void WeatherDialog::onForecastAreaChanged (QDateTime begin, QDateTime end)
{
QLinearGradient plotAreaGradient;
plotAreaGradient.setStart(QPointF(0, 0));
plotAreaGradient.setFinalStop(QPointF(1, 0));
plotAreaGradient.setCoordinateMode(QGradient::ObjectBoundingMode);

auto interpolateDt = [&begin, &end](const long long int dt)
{
return static_cast<double>(dt-begin.toMSecsSinceEpoch())/(end.toMSecsSinceEpoch()-begin.toMSecsSinceEpoch());
};

struct tm t;
for(int i = 0; i < m_forecast->size(); ++i)
{
const auto &entry = m_forecast->at(i);
const auto sunTimes = computeSunriseSunset(entry, m_config->longitude, m_config->latitude);
const auto entryDt = static_cast<unsigned long long>(entry.dt);
const bool isDay = entryDt > sunTimes.first && entryDt < sunTimes.second;

unixTimeStampToDate(t, entry.dt);
const auto dtTime = QDateTime{QDate{t.tm_year + 1900, t.tm_mon + 1, t.tm_mday}, QTime{t.tm_hour, t.tm_min, t.tm_sec}};
const auto msec = dtTime.toMSecsSinceEpoch();

double entryTime = interpolateDt(msec);
if(msec < begin.toMSecsSinceEpoch()) entryTime = 0;
if(msec > end.toMSecsSinceEpoch()) entryTime = 1;

plotAreaGradient.setColorAt(entryTime, isDay ? Qt::white:Qt::lightGray);
}

auto chart = m_weatherChart->chart();
chart->setPlotAreaBackgroundBrush(plotAreaGradient);
chart->setPlotAreaBackgroundVisible(true);
chart->update();
}
7 changes: 7 additions & 0 deletions WeatherDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,13 @@ class WeatherDialog
*/
void onUVAreaChanged(QDateTime begin, QDateTime end);

/** \brief Updates the background of the forecast chart on zoom.
* \param[in] begin Begin point in X axis.
* \param[in] end End point in X axis.
*
*/
void onForecastAreaChanged(QDateTime begin, QDateTime end);

private:
/** \brief Returns the color of the given aqi value.
* \param[in] aqiValue aqi value in [1,5].
Expand Down
12 changes: 6 additions & 6 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ Weather dialog, showing the current weather tab.

![weather](https://user-images.githubusercontent.com/12167134/127046991-e2eb1e5c-73d7-4ece-b9c4-dfff8dd1648e.png)

Weather forecast for the next days. If the user puts the mouse over a point in the temperature line or a bar a tooltip will provide the weather conditions for that day and hour.
Weather forecast for the next days. If the user puts the mouse over a point in the temperature line or a bar a tooltip will provide the weather conditions for that day and hour. Background is colored to day/night.
The graph can be zoomed by selecting the area to zoom with the mouse and resetted to the initial state by using the reset button below the graph. Data series can be hidden and shown again by clicking on its legend text.

![forecast_graph](https://user-images.githubusercontent.com/12167134/109207324-4b36e800-77a9-11eb-9891-291c907d0aef.png)
![forecast_graph](https://user-images.githubusercontent.com/12167134/282960962-93cc1a0a-cd26-4dc1-a13f-267bf62361a6.png)

Pollution forecast can be obtained in the third tab, showing the projections for the next days. The chart can be zoomed in the X axis and
resetted by using the reset button below. The pollution chart also has a tooltip with detailed information for each point of the lines and
Expand Down Expand Up @@ -148,16 +148,16 @@ To the translation in your language. For example in Spanish it is:

# Repository information

**Version**: 1.26.1
**Version**: 1.27.0

**Status**: finished.

**cloc statistics**

| Language |files |blank |comment |code |
|:-----------------------------|--------------:|------------:|-----------------:|-----:|
| C++ | 10 | 1037 | 393 | 5120 |
| C/C++ Header | 10 | 283 | 829 | 933 |
| C++ | 10 | 1057 | 401 | 5189 |
| C/C++ Header | 10 | 285 | 840 | 935 |
| HTML | 1 | 33 | 0 | 150 |
| CMake | 1 | 19 | 11 | 125 |
| **Total** | **22** | **1372** | **1233** | **6328** |
| **Total** | **22** | **1394** | **1252** | **6399** |

0 comments on commit 2d47b7b

Please sign in to comment.