1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-02-22 12:54:14 +01:00

OP-102: fix for the compass 'jump': rotation now takes the shorter path, no jump anymore - testers welcome.

git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@1146 ebee16cc-31ac-478f-84a7-5cbb03baadba
This commit is contained in:
edouard 2010-07-20 12:50:47 +00:00 committed by edouard
parent bcbd89167a
commit 6ef51b0c4d

View File

@ -33,14 +33,12 @@
PFDGadgetWidget::PFDGadgetWidget(QWidget *parent) : QGraphicsView(parent) PFDGadgetWidget::PFDGadgetWidget(QWidget *parent) : QGraphicsView(parent)
{ {
// TODO: create a proper "needle" object instead of hardcoding all this
// which is ugly (but easy).
setMinimumSize(64,64); setMinimumSize(64,64);
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
setScene(new QGraphicsScene(this)); setScene(new QGraphicsScene(this));
//setRenderHints(QPainter::Antialiasing || QPainter::TextAntialiasing); //setRenderHints(QPainter::Antialiasing || QPainter::TextAntialiasing);
setRenderHints(QPainter::TextAntialiasing); //setRenderHints(QPainter::TextAntialiasing);
m_renderer = new QSvgRenderer(); m_renderer = new QSvgRenderer();
@ -60,7 +58,6 @@ PFDGadgetWidget::PFDGadgetWidget(QWidget *parent) : QGraphicsView(parent)
altitudeTarget = 0; altitudeTarget = 0;
altitudeValue = 0; altitudeValue = 0;
// This timer mechanism makes needles rotate smoothly // This timer mechanism makes needles rotate smoothly
connect(&dialTimer, SIGNAL(timeout()), this, SLOT(moveNeedles())); connect(&dialTimer, SIGNAL(timeout()), this, SLOT(moveNeedles()));
dialTimer.start(20); dialTimer.start(20);
@ -134,6 +131,8 @@ void PFDGadgetWidget::connectNeedles() {
\brief Updates the link stats \brief Updates the link stats
*/ */
void PFDGadgetWidget::updateLinkStatus(UAVObject *object1) { void PFDGadgetWidget::updateLinkStatus(UAVObject *object1) {
// TODO: find a way to avoid updating the graphics if the value
// has not changed since the last update
// Double check that the field exists: // Double check that the field exists:
QString st = QString("Status"); QString st = QString("Status");
QString tdr = QString("TxDataRate"); QString tdr = QString("TxDataRate");
@ -199,7 +198,17 @@ void PFDGadgetWidget::updateHeading(UAVObject *object1) {
// These factors assume some things about the PFD SVG, namely: // These factors assume some things about the PFD SVG, namely:
// - Heading value in degrees // - Heading value in degrees
// - Scale is 540 degrees large // - Scale is 540 degrees large
headingTarget = field->getDouble()*compassBandWidth/(-540);
// Corvus Corax: "If you want a smooth transition between two angles, It is usually solved that by substracting
// one from another, and if the result is >180 or <-180 I substract (respectively add) 360 degrees
// to it. That way you always get the "shorter difference" to turn in."
double fac = compassBandWidth/540;
headingTarget = field->getDouble()*(-fac);
if ((headingValue - headingTarget)/fac > 180) {
headingTarget += 360*fac;
} else if (((headingValue - headingTarget)/fac < -180)) {
headingTarget -= 360*fac;
}
} else { } else {
qDebug() << "UpdateHeading: Wrong field, maybe an issue with object disconnection ?"; qDebug() << "UpdateHeading: Wrong field, maybe an issue with object disconnection ?";
} }
@ -239,12 +248,15 @@ void PFDGadgetWidget::updateHeading(UAVObject *object1) {
\brief Called by the UAVObject which got updated \brief Called by the UAVObject which got updated
*/ */
void PFDGadgetWidget::updateAirspeed(UAVObject *object3) { void PFDGadgetWidget::updateAirspeed(UAVObject *object3) {
Q_UNUSED(object3);
} }
/*! /*!
\brief Called by the UAVObject which got updated \brief Called by the UAVObject which got updated
*/ */
void PFDGadgetWidget::updateAltitude(UAVObject *object3) { void PFDGadgetWidget::updateAltitude(UAVObject *object3) {
Q_UNUSED(object3);
} }
@ -252,6 +264,8 @@ void PFDGadgetWidget::updateAltitude(UAVObject *object3) {
\brief Called by the UAVObject which got updated \brief Called by the UAVObject which got updated
*/ */
void PFDGadgetWidget::updateBattery(UAVObject *object1) { void PFDGadgetWidget::updateBattery(UAVObject *object1) {
// TODO: find a way to avoid updating the graphics if the value
// has not changed since the last update
// Double check that the field exists: // Double check that the field exists:
QString voltage = QString("Voltage"); QString voltage = QString("Voltage");
QString current = QString("Current"); QString current = QString("Current");
@ -702,6 +716,7 @@ void PFDGadgetWidget::paint()
void PFDGadgetWidget::paintEvent(QPaintEvent *event) void PFDGadgetWidget::paintEvent(QPaintEvent *event)
{ {
Q_UNUSED(event);
// Skip painting until the dial file is loaded // Skip painting until the dial file is loaded
if (! m_renderer->isValid()) { if (! m_renderer->isValid()) {
qDebug() << "Dial file not loaded, not rendering"; qDebug() << "Dial file not loaded, not rendering";
@ -715,6 +730,7 @@ void PFDGadgetWidget::paintEvent(QPaintEvent *event)
// nature of SVG dials. // nature of SVG dials.
void PFDGadgetWidget::resizeEvent(QResizeEvent *event) void PFDGadgetWidget::resizeEvent(QResizeEvent *event)
{ {
Q_UNUSED(event);
fitInView(m_background, Qt::KeepAspectRatio ); fitInView(m_background, Qt::KeepAspectRatio );
} }
@ -745,124 +761,147 @@ void PFDGadgetWidget::moveNeedles()
////// //////
// Roll // Roll
////// //////
double rollDiff; if (rollValue != rollTarget) {
if ((abs((rollValue-rollTarget)*10) > 5)) { double rollDiff;
rollDiff =(rollTarget - rollValue)/5; if ((abs((rollValue-rollTarget)*10) > 5)) {
rollDiff =(rollTarget - rollValue)/5;
} else {
rollDiff = rollTarget - rollValue;
dialCount--;
}
m_world->setRotation(m_world->rotation()+rollDiff);
m_rollscale->setRotation(m_rollscale->rotation()+rollDiff);
rollValue += rollDiff;
} else { } else {
rollDiff = rollTarget - rollValue;
dialCount--; dialCount--;
} }
m_world->setRotation(m_world->rotation()+rollDiff);
m_rollscale->setRotation(m_rollscale->rotation()+rollDiff);
rollValue += rollDiff;
////// //////
// Pitch // Pitch
////// //////
double pitchDiff; if (pitchValue != pitchTarget) {
if ((abs((pitchValue-pitchTarget)*10) > 5)) { double pitchDiff;
pitchDiff = (pitchTarget - pitchValue)/5; if ((abs((pitchValue-pitchTarget)*10) > 5)) {
pitchDiff = (pitchTarget - pitchValue)/5;
} else {
pitchDiff = pitchTarget - pitchValue;
dialCount--;
}
QPointF opd = QPointF(0,pitchDiff);
m_world->setTransform(QTransform::fromTranslate(opd.x(),opd.y()), true);
QPointF oop = m_world->transformOriginPoint();
m_world->setTransformOriginPoint((oop.x()-opd.x()),(oop.y()-opd.y()));
pitchValue += pitchDiff;
} else { } else {
pitchDiff = pitchTarget - pitchValue;
dialCount--; dialCount--;
} }
QPointF opd = QPointF(0,pitchDiff);
m_world->setTransform(QTransform::fromTranslate(opd.x(),opd.y()), true);
QPointF oop = m_world->transformOriginPoint();
m_world->setTransformOriginPoint((oop.x()-opd.x()),(oop.y()-opd.y()));
pitchValue += pitchDiff;
////// //////
// Heading // Heading
//
// If you want a smooth transition between two angles, It is usually solved that by substracting
// one from another, and if the result is >180 or <-180 I substract (respectively add) 360 degrees
// to it. That way you always get the "shorter difference" to turn in.
////// //////
double headingOffset = 0; if (headingValue != headingTarget) {
double headingDiff; double headingOffset = 0;
if ((abs((headingValue-headingTarget)*10) > 5)) { double headingDiff;
headingDiff = (headingTarget - headingValue)/5; if ((abs((headingValue-headingTarget)*10) > 5)) {
} else { headingDiff = (headingTarget - headingValue)/5;
headingDiff = headingTarget-headingValue; } else {
headingDiff = headingTarget-headingValue;
dialCount--;
}
double threshold = -180*compassBandWidth/540;
// Note: rendering can jump oh so very slightly when crossing the 180 degree
// boundary, should not impact actual useability of the display.
if ((headingValue < threshold) && ((headingValue+headingDiff)>=threshold)) {
// We went over 180°: activate a -360 degree offset
headingOffset = 2*threshold;
} else if ((headingValue >= threshold) && ((headingValue+headingDiff)<threshold)) {
// We went under 180°: remove the -360 degree offset
headingOffset = -2*threshold;
}
QPointF opd = QPointF(headingDiff+headingOffset,0);
m_compassband->setTransform(QTransform::fromTranslate(opd.x(),opd.y()), true);
headingValue += headingDiff;
} else {
dialCount--; dialCount--;
} }
double threshold = -180*compassBandWidth/540;
// Note: rendering can jump oh so very slightly when crossing the 180 degree
// boundary, should not impact actual useability of the display.
if ((headingValue < threshold) && ((headingValue+headingDiff)>=threshold)) {
// We went over 180<38>: activate a -360 degree offset
headingOffset = 2*threshold;
} else if ((headingValue >= threshold) && ((headingValue+headingDiff)<threshold)) {
// We went under 180<38>: remove the -360 degree offset
headingOffset = -2*threshold;
}
opd = QPointF(headingDiff+headingOffset,0);
m_compassband->setTransform(QTransform::fromTranslate(opd.x(),opd.y()), true);
headingValue += headingDiff;
////// //////
// Speed // Speed
////// //////
if (abs(groundspeedValue-groundspeedTarget) > speedScaleHeight/120) { if (groundspeedValue != groundspeedTarget) {
groundspeedValue += (groundspeedTarget-groundspeedValue)/5; if (abs(groundspeedValue-groundspeedTarget) > speedScaleHeight/120) {
} else { groundspeedValue += (groundspeedTarget-groundspeedValue)/5;
groundspeedValue = groundspeedTarget; } else {
dialCount--; groundspeedValue = groundspeedTarget;
} dialCount--;
qreal x = m_speedscale->transform().dx();
//opd = QPointF(x,fmod(groundspeedValue,speedScaleHeight/6));
// fmod does rounding errors!! the formula below works better:
opd = QPointF(x,groundspeedValue-floor(groundspeedValue/speedScaleHeight*6)*speedScaleHeight/6);
m_speedscale->setTransform(QTransform::fromTranslate(opd.x(),opd.y()), false);
double speedText = groundspeedValue/speedScaleHeight*30;
QString s = QString().sprintf("%.0f",speedText);
m_speedtext->setPlainText(s);
// TODO: optimize this by skipping if not necessary...
// Now update the text elements inside the scale:
// (Qt documentation states that the list has the same order
// as the item add order in the QGraphicsItemGroup)
QList <QGraphicsItem *> textList = m_speedscale->childItems();
qreal val = 5*floor(groundspeedValue/speedScaleHeight*6)+20;
foreach( QGraphicsItem * item, textList) {
if (QGraphicsTextItem *text = qgraphicsitem_cast<QGraphicsTextItem *>(item)) {
QString s = (val<0) ? QString() : QString().sprintf("%.0f",val);
text->setPlainText(s);
val -= 5;
} }
qreal x = m_speedscale->transform().dx();
//opd = QPointF(x,fmod(groundspeedValue,speedScaleHeight/6));
// fmod does rounding errors!! the formula below works better:
QPointF opd = QPointF(x,groundspeedValue-floor(groundspeedValue/speedScaleHeight*6)*speedScaleHeight/6);
m_speedscale->setTransform(QTransform::fromTranslate(opd.x(),opd.y()), false);
double speedText = groundspeedValue/speedScaleHeight*30;
QString s = QString().sprintf("%.0f",speedText);
m_speedtext->setPlainText(s);
// TODO: optimize this by skipping if not necessary...
// Now update the text elements inside the scale:
// (Qt documentation states that the list has the same order
// as the item add order in the QGraphicsItemGroup)
QList <QGraphicsItem *> textList = m_speedscale->childItems();
qreal val = 5*floor(groundspeedValue/speedScaleHeight*6)+20;
foreach( QGraphicsItem * item, textList) {
if (QGraphicsTextItem *text = qgraphicsitem_cast<QGraphicsTextItem *>(item)) {
QString s = (val<0) ? QString() : QString().sprintf("%.0f",val);
text->setPlainText(s);
val -= 5;
}
}
} else {
dialCount--;
} }
////// //////
// Altitude // Altitude
////// //////
if (abs(altitudeValue-altitudeTarget) > altitudeScaleHeight/120) { if (altitudeValue != altitudeTarget) {
altitudeValue += (altitudeTarget-altitudeValue)/5; if (abs(altitudeValue-altitudeTarget) > altitudeScaleHeight/120) {
altitudeValue += (altitudeTarget-altitudeValue)/5;
} else {
altitudeValue = altitudeTarget;
dialCount--;
}
qreal x = m_altitudescale->transform().dx();
//opd = QPointF(x,fmod(altitudeValue,altitudeScaleHeight/6));
// fmod does rounding errors!! the formula below works better:
QPointF opd = QPointF(x,altitudeValue-floor(altitudeValue/altitudeScaleHeight*6)*altitudeScaleHeight/6);
m_altitudescale->setTransform(QTransform::fromTranslate(opd.x(),opd.y()), false);
double altitudeText = altitudeValue/altitudeScaleHeight*30;
QString s = QString().sprintf("%.0f",altitudeText);
m_altitudetext->setPlainText(s);
// TODO: optimize this by skipping if not necessary...
// Now update the text elements inside the scale:
// (Qt documentation states that the list has the same order
// as the item add order in the QGraphicsItemGroup)
QList <QGraphicsItem *> textList = m_altitudescale->childItems();
qreal val = 5*floor(altitudeValue/altitudeScaleHeight*6)+20;
foreach( QGraphicsItem * item, textList) {
if (QGraphicsTextItem *text = qgraphicsitem_cast<QGraphicsTextItem *>(item)) {
QString s = (val<0) ? QString() : QString().sprintf("%.0f",val);
text->setPlainText(s);
val -= 5;
}
}
} else { } else {
altitudeValue = altitudeTarget;
dialCount--; dialCount--;
} }
x = m_altitudescale->transform().dx();
//opd = QPointF(x,fmod(altitudeValue,altitudeScaleHeight/6));
// fmod does rounding errors!! the formula below works better:
opd = QPointF(x,altitudeValue-floor(altitudeValue/altitudeScaleHeight*6)*altitudeScaleHeight/6);
m_altitudescale->setTransform(QTransform::fromTranslate(opd.x(),opd.y()), false);
double altitudeText = altitudeValue/altitudeScaleHeight*30;
s = QString().sprintf("%.0f",altitudeText);
m_altitudetext->setPlainText(s);
// TODO: optimize this by skipping if not necessary...
// Now update the text elements inside the scale:
// (Qt documentation states that the list has the same order
// as the item add order in the QGraphicsItemGroup)
textList = m_altitudescale->childItems();
val = 5*floor(altitudeValue/altitudeScaleHeight*6)+20;
foreach( QGraphicsItem * item, textList) {
if (QGraphicsTextItem *text = qgraphicsitem_cast<QGraphicsTextItem *>(item)) {
QString s = (val<0) ? QString() : QString().sprintf("%.0f",val);
text->setPlainText(s);
val -= 5;
}
}
//update();
if (!dialCount) if (!dialCount)
dialTimer.stop(); dialTimer.stop();
} }