From 53707ff5062927329e88cbfbe17b8e27ce51c5f6 Mon Sep 17 00:00:00 2001 From: Max Maisel Date: Sat, 23 Apr 2022 15:51:08 +0200 Subject: [PATCH] Draw sensor status like an artificial horizon This should be easier to understand than the previous cabinet projection. Furthermore, fix "jumping" of the sensor dialog when the length of the decimal representation of the sensor values changes. Finally, always get and set sensor dead and max zones in degree. There are converted to redians internally. --- src/globalvariables.cpp | 8 +- src/gui/joysensoreditdialog.cpp | 41 ++-- src/gui/joysensoreditdialog.ui | 395 ++++++++++++++----------------- src/gui/joystickstatuswindow.cpp | 6 +- src/joysensor.cpp | 28 ++- src/joysensorstatusbox.cpp | 179 ++++++++------ src/joysensorstatusbox.h | 2 +- 7 files changed, 335 insertions(+), 324 deletions(-) diff --git a/src/globalvariables.cpp b/src/globalvariables.cpp index 5a992b7e2..680acdb6c 100644 --- a/src/globalvariables.cpp +++ b/src/globalvariables.cpp @@ -184,11 +184,11 @@ const int GlobalVariables::JoyControlStick::DEFAULTSTICKDELAY = 0; // ---- JoySensor ---- // -const double GlobalVariables::JoySensor::ACCEL_MIN = -30.0; -const double GlobalVariables::JoySensor::ACCEL_MAX = 30.0; +const double GlobalVariables::JoySensor::ACCEL_MIN = -90.0; +const double GlobalVariables::JoySensor::ACCEL_MAX = 90.0; const double GlobalVariables::JoySensor::GRAVITY = 9.80665; -const double GlobalVariables::JoySensor::GYRO_MIN = -10.0; -const double GlobalVariables::JoySensor::GYRO_MAX = 10.0; +const double GlobalVariables::JoySensor::GYRO_MIN = -360.0; +const double GlobalVariables::JoySensor::GYRO_MAX = 360.0; const double GlobalVariables::JoySensor::DEFAULTDEADZONE = 0.5; const int GlobalVariables::JoySensor::DEFAULTDIAGONALRANGE = 45; const unsigned int GlobalVariables::JoySensor::DEFAULTSENSORDELAY = 0; diff --git a/src/gui/joysensoreditdialog.cpp b/src/gui/joysensoreditdialog.cpp index f15906d39..0283fa0fd 100644 --- a/src/gui/joysensoreditdialog.cpp +++ b/src/gui/joysensoreditdialog.cpp @@ -48,27 +48,10 @@ JoySensorEditDialog::JoySensorEditDialog(JoySensor *sensor, QWidget *parent) updateWindowTitleSensorName(); - m_ui->deadZoneSlider->setValue(m_sensor->getDeadZone()); - m_ui->deadZoneSpinBox->setValue(m_sensor->getDeadZone()); - - m_ui->maxZoneSlider->setValue(m_sensor->getMaxZone()); - m_ui->maxZoneSpinBox->setValue(m_sensor->getMaxZone()); - - m_ui->diagonalRangeSlider->setValue(m_sensor->getDiagonalRange()); - m_ui->diagonalRangeSpinBox->setValue(m_sensor->getDiagonalRange()); - - QString xCoorString = QString::number(m_sensor->getXCoordinate()); - m_ui->xCoordinateValue->setText(xCoorString); - - QString yCoorString = QString::number(m_sensor->getYCoordinate()); - m_ui->yCoordinateValue->setText(yCoorString); - - QString zCoorString = QString::number(m_sensor->getZCoordinate()); - m_ui->zCoordinateValue->setText(zCoorString); - - auto min_width = m_ui->xCoordinateLabel->fontMetrics(). + auto min_width = m_ui->xCoordinateValue->fontMetrics(). boundingRect(QString("X.XXXXXXX")).width(); - m_ui->xCoordinateLabel->setMinimumWidth(min_width); + m_ui->xCoordinateValue->setMinimumWidth(min_width); + m_ui->xCoordinateValue->setAlignment(Qt::AlignLeft); if (m_sensor->getType() == JoySensor::ACCELEROMETER) { @@ -95,6 +78,24 @@ JoySensorEditDialog::JoySensorEditDialog(JoySensor *sensor, QWidget *parent) m_ui->maxZoneSpinBox->setMaximum(GlobalVariables::JoySensor::GYRO_MAX); } + m_ui->deadZoneSlider->setValue(m_sensor->getDeadZone()); + m_ui->deadZoneSpinBox->setValue(m_sensor->getDeadZone()); + + m_ui->maxZoneSlider->setValue(m_sensor->getMaxZone()); + m_ui->maxZoneSpinBox->setValue(m_sensor->getMaxZone()); + + m_ui->diagonalRangeSlider->setValue(m_sensor->getDiagonalRange()); + m_ui->diagonalRangeSpinBox->setValue(m_sensor->getDiagonalRange()); + + QString xCoorString = QString::number(m_sensor->getXCoordinate()); + m_ui->xCoordinateValue->setText(xCoorString); + + QString yCoorString = QString::number(m_sensor->getYCoordinate()); + m_ui->yCoordinateValue->setText(yCoorString); + + QString zCoorString = QString::number(m_sensor->getZCoordinate()); + m_ui->zCoordinateValue->setText(zCoorString); + m_ui->sensorStatusBoxWidget->setSensor(m_sensor); selectCurrentPreset(); diff --git a/src/gui/joysensoreditdialog.ui b/src/gui/joysensoreditdialog.ui index dff575005..83a113968 100644 --- a/src/gui/joysensoreditdialog.ui +++ b/src/gui/joysensoreditdialog.ui @@ -94,225 +94,194 @@ - - - 10 - - - - - - - - 0 - 0 - - - - X (m/s^2): - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - 0 - - - - + + + + + + 0 + 0 + + + + 0 + + - - - - - - - 0 - 0 - - - - Y (m/s^2): - - - - - - - - 0 - 0 - - - - 0 - - - - + + + + + 0 + 0 + + + + X (m/s^2): + + - - - - - - - 0 - 0 - - - - Z (m/s^2): - - - - - - - - 0 - 0 - - - - 0 - - - - + + + + + 0 + 0 + + + + 0 + + - - - - - - - 0 - 0 - - - - Gravity (m/s^2): - - - - - - - - 0 - 0 - - - - 0 - - - - + + + + + 0 + 0 + + + + 0 + + - - - - - - - 0 - 0 - - - - Pitch (°): - - - - - - - - 0 - 0 - - - - 0 - - - - + + + + + 0 + 0 + + + + 0 + + - - - - - - - 0 - 0 - - - - Roll (°): - - - - - - - - 0 - 0 - - - - 0 - - - - + + + + + 0 + 0 + + + + Gravity (m/s^2): + + - - - - - - - 0 - 0 - - - - % Safe Zone: - - - - - - - - 0 - 0 - - - - 0 - - - - + + + + + 0 + 0 + + + + 0 + + + + + + + + 0 + 0 + + + + Pitch (°): + + + + + + + + 0 + 0 + + + + Roll (°): + + + + + + + + 0 + 0 + + + + Z (m/s^2): + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + 0 + + + + + + + + 0 + 0 + + + + Y (m/s^2): + + + + + + + + 0 + 0 + + + + % Safe Zone: + + + + + + + + 0 + 0 + + + + 0 + + diff --git a/src/gui/joystickstatuswindow.cpp b/src/gui/joystickstatuswindow.cpp index 488575d16..d35074362 100644 --- a/src/gui/joystickstatuswindow.cpp +++ b/src/gui/joystickstatuswindow.cpp @@ -248,13 +248,13 @@ JoystickStatusWindow::JoystickStatusWindow(InputDevice *joystick, QWidget *paren m_gyro_axes[i]->setFormat("%v"); if (i == 0) { axisLabel->setText(tr("Gyroscope X")); - m_gyro_axes[i]->setValue(sensor->getXCoordinate()); + m_gyro_axes[i]->setValue(sensor->getXCoordinate() * 180 / M_PI); } else if (i == 1) { axisLabel->setText(tr("Gyroscope Y")); - m_gyro_axes[i]->setValue(sensor->getYCoordinate()); + m_gyro_axes[i]->setValue(sensor->getYCoordinate() * 180 / M_PI); } else { axisLabel->setText(tr("Gyroscope Z")); - m_gyro_axes[i]->setValue(sensor->getZCoordinate()); + m_gyro_axes[i]->setValue(sensor->getZCoordinate() * 180 / M_PI); } hbox->addWidget(axisLabel); hbox->addWidget(m_gyro_axes[i]); diff --git a/src/joysensor.cpp b/src/joysensor.cpp index da215babc..312cd45ba 100644 --- a/src/joysensor.cpp +++ b/src/joysensor.cpp @@ -170,7 +170,10 @@ JoySensor::Type JoySensor::getType() { return m_type; } * @brief Get the assigned dead zone value. * @return Assigned dead zone value */ -float JoySensor::getDeadZone() { return m_dead_zone; } +float JoySensor::getDeadZone() +{ + return m_dead_zone * 180 / M_PI; +} /** * @brief Get the assigned diagonal range value. @@ -178,7 +181,10 @@ float JoySensor::getDeadZone() { return m_dead_zone; } */ int JoySensor::getDiagonalRange() { return m_diagonal_range; } -float JoySensor::getMaxZone() { return m_max_zone; } +float JoySensor::getMaxZone() +{ + return m_max_zone * 180 / M_PI; +} /** * @brief Get the value for the corresponding X axis. @@ -626,12 +632,12 @@ void JoySensor::writeConfig(QXmlStreamWriter *xml) xml->writeAttribute("type", QString::number(m_type)); if (m_dead_zone != GlobalVariables::JoySensor::DEFAULTDEADZONE) - xml->writeTextElement("deadZone", QString::number(m_dead_zone)); + xml->writeTextElement("deadZone", QString::number(getDeadZone())); if (m_max_zone != (m_type == ACCELEROMETER ? GlobalVariables::JoySensor::ACCEL_MAX : GlobalVariables::JoySensor::GYRO_MAX)) - xml->writeTextElement("maxZone", QString::number(m_max_zone)); + xml->writeTextElement("maxZone", QString::number(getMaxZone())); if (m_diagonal_range != GlobalVariables::JoySensor::DEFAULTDIAGONALRANGE) xml->writeTextElement("diagonalRange", QString::number(m_diagonal_range)); @@ -684,6 +690,7 @@ void JoySensor::reset() void JoySensor::setDeadZone(float value) { + value = abs(value / 180 * M_PI); // XXX: do not compare floats if ((value != m_dead_zone) && (value <= m_max_zone)) { @@ -695,10 +702,7 @@ void JoySensor::setDeadZone(float value) void JoySensor::setMaxZone(float value) { - value = abs(value); - - // XXX: implement calibration - + value = abs(value / 180 * M_PI); // XXX: do not compare floats if ((value != m_max_zone) && (value > m_dead_zone)) { @@ -750,14 +754,14 @@ void JoySensor::createDeskEvent(bool safezone, bool ignoresets) double roll = calculateRoll(); if (safezone) { - if (pitch > M_PI/4) + if (pitch > m_dead_zone) eventbutton[0] = m_buttons.value(JoySensorDirection::ACCEL_UP); - else if(pitch < -M_PI/4) + else if(pitch < -m_dead_zone) eventbutton[0] = m_buttons.value(JoySensorDirection::ACCEL_DOWN); - if (roll > M_PI/4) + if (roll > m_dead_zone) eventbutton[1] = m_buttons.value(JoySensorDirection::ACCEL_LEFT); - else if (roll < -M_PI/4) + else if (roll < -m_dead_zone) eventbutton[1] = m_buttons.value(JoySensorDirection::ACCEL_RIGHT); if (distance > 20) diff --git a/src/joysensorstatusbox.cpp b/src/joysensorstatusbox.cpp index 170919d9d..997e4848b 100644 --- a/src/joysensorstatusbox.cpp +++ b/src/joysensorstatusbox.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include JoySensorStatusBox::JoySensorStatusBox(QWidget *parent) @@ -82,116 +83,152 @@ void JoySensorStatusBox::paintEvent(QPaintEvent *event) Q_UNUSED(event); PadderCommon::inputDaemonMutex.lock(); - if (m_sensor->getType() == JoySensor::ACCELEROMETER) - drawSensorBox(GlobalVariables::JoySensor::ACCEL_MAX); - else - drawSensorBox(GlobalVariables::JoySensor::GYRO_MAX); + drawArtificialHorizon(); PadderCommon::inputDaemonMutex.unlock(); } -void JoySensorStatusBox::drawSensorBox(float scale) +void JoySensorStatusBox::drawArtificialHorizon() { QPainter paint(this); paint.setRenderHint(QPainter::Antialiasing, true); - int side = qMin(width() - 2, height() - 2); + int side = qMin(width(), height()); + QPen pen; QPixmap pix(side, side); pix.fill(Qt::transparent); QPainter painter(&pix); painter.setRenderHint(QPainter::Antialiasing, true); - // Draw box outline - QPen pen; - pen.setColor(Qt::black); - pen.setWidth(1); - painter.setPen(pen); - painter.setBrush(Qt::NoBrush); - painter.drawRect(0, 0, side - 1, side - 1); + // Switch to centric coordinate system + painter.translate(side/2.0, side/2.0); + painter.scale(side*0.45, -side*0.45); painter.save(); - // Switch coordinate system - float window_scale = (scale * 2.0 + 1.0); - painter.scale(side / window_scale, side / window_scale); - painter.translate(window_scale/2.0, window_scale/2.0); + // Draw moving instrument parts + QPainterPath clippingPath; + clippingPath.addEllipse(QPointF(0, 0), 1, 1); + painter.setClipPath(clippingPath); - // Draw max zone and initial inner clear circle - float maxzone = m_sensor->getMaxZone(); - pen.setWidthF(scale/10.0); - painter.setPen(pen); - painter.setOpacity(0.5); - painter.setBrush(Qt::darkGreen); - painter.drawEllipse(QPointF(0.0, 0.0), scale, scale); - painter.setCompositionMode(QPainter::CompositionMode_Clear); - painter.setPen(Qt::NoPen); - painter.drawEllipse(QPointF(0.0, 0.0), maxzone, maxzone); + float pitch, roll, yaw; + if (m_sensor->getType() == JoySensor::ACCELEROMETER) + { + pitch = -m_sensor->calculatePitch(); + roll = m_sensor->calculateRoll(); + yaw = 0; + } else + { + pitch = -m_sensor->getXCoordinate(); + roll = m_sensor->getYCoordinate(); + yaw = -m_sensor->getZCoordinate(); + } + pitch = qBound(-180.0, pitch * 180 / M_PI, 180.0); + roll = qBound(-180.0, roll * 180 / M_PI, 180.0); + yaw = qBound(-180.0, yaw * 180 / M_PI, 180.0); + painter.translate(yaw / 90, pitch / 90); + painter.rotate(roll); - painter.setCompositionMode(QPainter::CompositionMode_SourceOver); - painter.setOpacity(1.0); + pen.setColor(Qt::transparent); + painter.setPen(pen); + painter.setBrush(QBrush(QColor(64, 128, 255))); + painter.drawRect(QRectF(-10, 0, 20, 10)); + painter.setBrush(QBrush(Qt::black)); + painter.drawRect(QRectF(-10, -10, 20, 10)); + + // Draw dead zone + pen.setColor(Qt::red); + pen.setWidthF(0.02); + painter.setPen(pen); + painter.setBrush(QBrush(QColor(255, 0, 0, 128))); + float deadZone = m_sensor->getDeadZone(); + painter.drawEllipse(QPointF(0, 0), deadZone/90, deadZone/90); + + // Draw max zone + QPainterPath maxZonePath; + float maxZone = m_sensor->getMaxZone(); + maxZonePath.addEllipse(QPointF(0, 0), 10, 10); + maxZonePath.addEllipse(QPointF(0, 0), maxZone/90, maxZone/90); + pen.setColor(Qt::darkGreen); + pen.setWidthF(0.02); + painter.setPen(pen); + painter.setBrush(QBrush(QColor(0, 128, 0, 128))); + painter.drawPath(maxZonePath); // Draw diagonal zones - pen.setWidth(0); - pen.setColor(Qt::black); + pen.setColor(Qt::green); painter.setPen(pen); - painter.setOpacity(0.5); - painter.setBrush(QBrush(Qt::green)); + painter.setBrush(QBrush(QColor(0, 255, 0, 128))); for(int i = 0; i < 4; ++i) { painter.drawPie( - QRectF(-scale, -scale, scale * 2.0, scale * 2.0), + QRectF(-maxZone/90, -maxZone/90, 2*maxZone/90, 2*maxZone/90), (45 + 90*i - m_sensor->getDiagonalRange()/2) * 16, m_sensor->getDiagonalRange() * 16); } - painter.setOpacity(1.0); - // Draw deadzone circle - pen.setWidth(0); - painter.setPen(pen); - painter.setBrush(QBrush(Qt::red)); - painter.drawEllipse(QPointF(0.0, 0.0), - m_sensor->getDeadZone(), m_sensor->getDeadZone()); - - pen.setWidth(0); - painter.setBrush(QBrush(Qt::blue)); - pen.setColor(Qt::blue); + // Pitch scale: 30deg per line + pen.setColor(Qt::white); + pen.setWidthF(0.025); painter.setPen(pen); + painter.setBrush(QBrush(Qt::transparent)); + for(int j = -180; j <= 180; j+=30) { + painter.drawLine(QPointF(-10, j/90.0), QPointF(10, j/90.0)); + } - // Draw raw crosshair - float xsens = m_sensor->getXCoordinate(); - float ysens = m_sensor->getYCoordinate(); - float zsens = m_sensor->getZCoordinate(); + // Yaw scale: 30deg per line + if (m_sensor->getType() == JoySensor::GYROSCOPE) + { + pen.setColor(Qt::white); + pen.setWidthF(0.025); + painter.setPen(pen); + painter.setBrush(QBrush(Qt::transparent)); + for(int j = -180; j <= 180; j+=30) { + painter.drawLine(QPointF(j/90.0, -10), QPointF(j/90.0, 10)); + } + } - float xp = xsens + 0.5 * zsens; - float yp = ysens - 0.5 * zsens; + // Draw fixed instrument parts + painter.restore(); + painter.save(); + pen.setColor(QColor(80, 80, 80)); + pen.setWidthF(0.2); + painter.setPen(pen); + painter.setBrush(Qt::NoBrush); + painter.drawEllipse(QPointF(0, 0), 1, 1); - pen.setWidthF(scale/20.0); + // Draw scale + pen.setWidthF(0.05); + pen.setColor(Qt::yellow); painter.setPen(pen); - painter.drawLine(QPointF(xsens, ysens), QPointF(xp, yp)); - painter.setPen(Qt::NoPen); - painter.drawRect( - QRectF(xp-scale/20.0, yp-scale/20.0, scale/10.0, scale/10.0)); - painter.setBrush(QBrush(Qt::darkBlue)); - pen.setColor(Qt::darkBlue); + painter.drawLine(QPointF(0.3, 0), QPointF(0.2, 0)); + painter.drawLine(QPointF(-0.3, 0), QPointF(-0.2, 0)); + painter.drawArc(QRectF(-0.2, -0.2, 0.4, 0.4), 0*16, 180*16); + painter.drawPoint(QPointF(0, 0)); + + pen.setColor(Qt::white); painter.setPen(pen); + for (int j = 0; j < 19; ++j) { + painter.drawLine(QPointF(1, 0), QPointF(0.9, 0)); + painter.rotate(10.0); + } - // Back to window coordinate system. + // Draw dead zone painter.restore(); - pen.setWidth(0); - pen.setColor(Qt::black); - painter.setPen(pen); - painter.scale(side / 2, side / 2); - painter.translate(1, 1); + pen.setColor(Qt::red); + pen.setWidthF(0.1); painter.setPen(pen); painter.setOpacity(0.5); - // Draw Y line - painter.drawLine(QPointF(0.0, -1.0), QPointF(0.0, 1.0)); - // Draw X line - painter.drawLine(QPointF(-1.0, 0.0), QPointF(1.0, 0.0)); - // Draw Z line - painter.setOpacity(0.25); - painter.drawLine(QPointF(-0.5, 0.5), QPointF(0.5, -0.5)); + painter.drawArc(QRectF(-1, -1, 2, 2), -16*deadZone, 16*deadZone*2); + painter.drawArc(QRectF(-1, -1, 2, 2), 16*(180-deadZone), 16*deadZone*2); + + // Draw max zone + pen.setColor(Qt::darkGreen); + painter.setPen(pen); + float tmpMaxZone = std::min(maxZone, 90.0f); + painter.drawArc(QRectF(-1, -1, 2, 2), 16*(90-(90-tmpMaxZone)), 16*(90-tmpMaxZone)*2); + painter.drawArc(QRectF(-1, -1, 2, 2), 16*(270-(90-tmpMaxZone)), 16*(90-tmpMaxZone)*2); // Draw to window paint.setCompositionMode(QPainter::CompositionMode_SourceOver); diff --git a/src/joysensorstatusbox.h b/src/joysensorstatusbox.h index d47f5f5e8..ef8e326e1 100644 --- a/src/joysensorstatusbox.h +++ b/src/joysensorstatusbox.h @@ -39,7 +39,7 @@ class JoySensorStatusBox : public QWidget protected: virtual void paintEvent(QPaintEvent *event); - void drawSensorBox(float scale); + void drawArtificialHorizon(); private: JoySensor *m_sensor;