Add Elevation Widget to Train Video Overlays (#3411)

* 1 - Add forceSquareRatio to MeterWidget
* 2 - Adjust default colors and add background text.
* 3 - Add Elevation widget, included in default layout visible only on slope mode.
Based on the work done by Vianney Voyer
Co-authored-by: Peter <pkanatselis@gmail.com>
This commit is contained in:
human705
2020-04-30 18:26:40 -04:00
committed by GitHub
parent a0add0bdc9
commit 05ee4f40da
5 changed files with 155 additions and 10 deletions

View File

@@ -83,4 +83,13 @@
<MainColor R="255" G="0" B="0" A="180" />
<Text>load</Text>
</meter>
<!-- START Changes for elevation widget -->
<meter name="elevation" container="Video" source="Elevation" type="Elevation">
<RelativeSize Width="40.0" Height="15.0" />
<RelativePosition X="20.0" Y="92.0" />
<BackgroundColor R="200" G="200" B="200" A="125" />
<OutlineColor R="255" G="255" B="255" A="250" />
<MainColor R="255" G="0" B="0" A="250" />
</meter>
<!-- END Changes for elevation widget -->
</layout>

View File

@@ -19,6 +19,8 @@
#include <QtGui>
#include <QGraphicsPathItem>
#include "MeterWidget.h"
#include "ErgFile.h"
#include "Context.h"
MeterWidget::MeterWidget(QString Name, QWidget *parent, QString Source) : QWidget(parent), m_Name(Name), m_container(parent), m_Source(Source)
{
@@ -37,12 +39,13 @@ MeterWidget::MeterWidget(QString Name, QWidget *parent, QString Source) : QWidge
m_OutlineColor = QColor(128,128,128,180);
m_MainFont = QFont(this->font().family(), 64);
m_AltFont = QFont(this->font().family(), 48);
m_BackgroundColor = QColor(96, 96, 96, 200);
m_BackgroundColor = QColor(96, 96, 96, 0);
m_RangeMin = 0;
m_RangeMax = 100;
m_Angle = 180.0;
m_SubRange = 10;
boundingRectVisibility = false;
forceSquareRatio = true;
}
void MeterWidget::SetRelativeSize(float RelativeWidth, float RelativeHeight)
@@ -75,7 +78,15 @@ void MeterWidget::AdjustSizePos()
void MeterWidget::ComputeSize()
{
m_Width = m_Height = (m_container->width() * m_RelativeWidth + m_container->height() * m_RelativeHeight) / 2;
if (forceSquareRatio)
{
m_Width = m_Height = (m_container->width() * m_RelativeWidth + m_container->height() * m_RelativeHeight) / 2;
}
else
{
m_Width = m_container->width() * m_RelativeWidth;
m_Height = m_container->height() * m_RelativeHeight;
}
}
QSize MeterWidget::sizeHint() const
@@ -119,12 +130,7 @@ void MeterWidget::setBoundingRectVisibility(bool show, QColor boundingRectColor
TextMeterWidget::TextMeterWidget(QString Name, QWidget *parent, QString Source) : MeterWidget(Name, parent, Source)
{
}
void TextMeterWidget::ComputeSize()
{
m_Width = m_container->width() * m_RelativeWidth;
m_Height = m_container->height() * m_RelativeHeight;
forceSquareRatio = false;
}
void TextMeterWidget::paintEvent(QPaintEvent* paintevent)
@@ -132,6 +138,7 @@ void TextMeterWidget::paintEvent(QPaintEvent* paintevent)
MeterWidget::paintEvent(paintevent);
m_MainBrush = QBrush(m_MainColor);
m_BackgroundBrush = QBrush(m_BackgroundColor);
m_OutlinePen = QPen(m_OutlineColor);
m_OutlinePen.setWidth(1);
m_OutlinePen.setStyle(Qt::SolidLine);
@@ -140,6 +147,12 @@ void TextMeterWidget::paintEvent(QPaintEvent* paintevent)
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
//draw background
painter.setPen(Qt::NoPen);
painter.setBrush(m_BackgroundBrush);
if (Text!=QString(""))
painter.drawRect (0, 0, m_Width, m_Height);
QPainterPath my_painterPath;
my_painterPath.addText(QPointF(0,0),m_MainFont,Text);
my_painterPath.addText(QPointF(QFontMetrics(m_MainFont).width(Text), 0),m_AltFont,AltText);
@@ -297,3 +310,94 @@ void NeedleMeterWidget::paintEvent(QPaintEvent* paintevent)
painter.drawPath(my_painterPath);
painter.restore();
}
ElevationMeterWidget::ElevationMeterWidget(QString Name, QWidget *parent, QString Source, Context *context) : MeterWidget(Name, parent, Source), context(context)
{
forceSquareRatio = false;
gradientValue = 0.0;
}
void ElevationMeterWidget::paintEvent(QPaintEvent* paintevent)
{
// TODO : show Power when not in slope simulation mode
if (!context || !context->currentErgFile() || context->currentErgFile()->Points.size()<=1)
return;
MeterWidget::paintEvent(paintevent);
m_MainBrush = QBrush(m_MainColor);
m_BackgroundBrush = QBrush(m_BackgroundColor);
m_OutlinePen = QPen(m_OutlineColor);
m_OutlinePen.setWidth(1);
m_OutlinePen.setStyle(Qt::SolidLine);
//painter
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
// Find min/max
double minX, minY, maxX, maxY, cyclistX=0.0;
// (based on ErgFilePlot.cpp)
minX=maxX=context->currentErgFile()->Points[0].x; // meters
minY=maxY=context->currentErgFile()->Points[0].y; // meters or altitude???
foreach(ErgFilePoint x, context->currentErgFile()->Points)
{
if (x.y > maxY) maxY = x.y;
if (x.x > maxX) maxX = x.x;
if (x.y < minY) minY = x.y;
if (x.x < minX) minX = x.x;
}
// check if slope shown will not be too inconsistent (based on widget's width/height ratio)
// we accept 20 times i.e. 5% gradient will be shown as 45°
if ( m_Width!=0 && (maxY-minY) / 0.05 < (double)m_Height * 0.80 * (maxX-minX) / (double)m_Width)
maxY = minY + (double)m_Height * 0.80 * (maxX-minX) / (double)m_Width * 0.05;
double bubbleSize = (double)m_Height*0.010f;
minY -= (maxY-minY) * 0.20f; // add 20% as bottom headroom (slope gradient will be shown there in a bubble)
// this->Value should hold the current distance in meters.
cyclistX = (this->Value * 1000.0 - minX) * (double)m_Width / (maxX-minX);
//Get point to create the polygon
QPolygon polygon;
polygon << QPoint(0.0, (double)m_Height);
double x, y, pt=0;
double nextX = 1;
for( pt=0; pt < context->currentErgFile()->Points.size(); pt++)
{
for ( ; x < nextX && pt < context->currentErgFile()->Points.size(); pt++)
{
x = (context->currentErgFile()->Points[pt].x - minX) * (double)m_Width / (maxX-minX);
y = (context->currentErgFile()->Points[pt].y - minY) * (double)m_Height / (maxY-minY);
}
// Add points to polygon only once every time the x coordinate integer part changes.
polygon << QPoint(x, (double)m_Height - y);
nextX = floor(x) + 1.0;
}
polygon << QPoint((double) m_Width, (double)m_Height);
polygon << QPoint(fmin((double) m_Width,cyclistX+bubbleSize), (double)m_Height);
polygon << QPoint(cyclistX, (double)m_Height-bubbleSize);
polygon << QPoint(fmax(0.0, cyclistX-bubbleSize), (double)m_Height);
painter.setPen(m_OutlinePen);
painter.setBrush(m_BackgroundBrush);
painter.drawPolygon(polygon);
m_OutlinePen = QPen(m_MainColor);
m_OutlinePen.setWidth(1);
m_OutlinePen.setStyle(Qt::SolidLine);
painter.setPen(m_OutlinePen);
painter.drawLine(cyclistX, 0.0, cyclistX, (double)m_Height-bubbleSize);
//Cosmetic enhancment: Display grade as #.#%
std::string sGrad;
QString s_grad ="";
s_grad = ((-1.0 < this->gradientValue && this->gradientValue < 0.0)?QString("-"):QString("")) + QString::number((int) this->gradientValue);
s_grad += QString(".") + QString::number(abs((int)(this->gradientValue * 10.0) % 10)) + QString("%");
// Display gradient text to the right of the line until the middle, then display to the left of the line
if (cyclistX < m_Width*0.5) {
painter.drawText((double)cyclistX+5, ((double)m_Height * 0.95), s_grad);
} else {
painter.drawText((double)cyclistX-45, ((double)m_Height * 0.95), s_grad);
}
}

View File

@@ -20,6 +20,7 @@
#define _MeterWidget_h 1
#include <QWidget>
#include "Context.h"
class MeterWidget : public QWidget
{
@@ -59,6 +60,7 @@ class MeterWidget : public QWidget
float m_RangeMin, m_RangeMax;
float m_Angle;
int m_SubRange;
bool forceSquareRatio;
QColor m_MainColor;
QColor m_ScaleColor;
@@ -83,7 +85,6 @@ class TextMeterWidget : public MeterWidget
{
public:
explicit TextMeterWidget(QString name, QWidget *parent = 0, QString Source = QString("None"));
virtual void ComputeSize();
virtual void paintEvent(QPaintEvent* paintevent);
};
@@ -109,5 +110,15 @@ class NeedleMeterWidget : public MeterWidget
virtual void paintEvent(QPaintEvent* paintevent);
};
class ElevationMeterWidget : public MeterWidget
{
public:
explicit ElevationMeterWidget(QString name, QWidget *parent = 0, QString Source = QString("None"), Context *context = NULL);
virtual void paintEvent(QPaintEvent* paintevent);
float gradientValue;
void setContext(Context *context) { this->context = context; }
private:
Context *context;
};
#endif // _MeterWidget_h

View File

@@ -47,7 +47,7 @@ void VideoLayoutParser::SetDefaultValues()
meterWidget->m_MainColor = QColor(255,0,0,200);
meterWidget->m_ScaleColor = QColor(255,255,255,200);
meterWidget->m_OutlineColor = QColor(100,100,100,200);
meterWidget->m_BackgroundColor = QColor(100,100,100,200);
meterWidget->m_BackgroundColor = QColor(100,100,100,0);
meterWidget->m_MainFont = QFont(meterWidget->font().family(), 64);
meterWidget->m_AltFont = QFont(meterWidget->font().family(), 48);
}
@@ -134,6 +134,10 @@ bool VideoLayoutParser::startElement( const QString&, const QString&,
{
meterWidget = new CircularBargraphMeterWidget(meterName, containerWidget, source);
}
else if (meterType == QString("Elevation"))
{
meterWidget = new ElevationMeterWidget(meterName, containerWidget, source);
}
else
{
qDebug() << QObject::tr("Error creating meter");

View File

@@ -316,6 +316,23 @@ void VideoWindow::telemetryUpdate(RealtimeData rtd)
p_meterWidget->Text = QString::number((int)p_meterWidget->Value);
p_meterWidget->AltText = QString(".") +QString::number((int)(p_meterWidget->Value * 10.0) - (((int) p_meterWidget->Value) * 10)) + (metric ? tr(" kph") : tr(" mph"));
}
else if (p_meterWidget->Source() == QString("Elevation"))
{
// Do not show in ERG mode
if (rtd.mode == ERG || rtd.mode == MRC)
{
p_meterWidget->setWindowOpacity(0); // Hide the widget
}
p_meterWidget->Value = rtd.getDistance();
ElevationMeterWidget* elevationMeterWidget = dynamic_cast<ElevationMeterWidget*>(p_meterWidget);
if (!elevationMeterWidget)
qDebug() << "Error: Elevation keyword used but widget is not elevation type";
else
{
elevationMeterWidget->setContext(context);
elevationMeterWidget->gradientValue = rtd.getSlope();
}
}
else if (p_meterWidget->Source() == QString("Cadence"))
{
p_meterWidget->Value = rtd.getCadence();