diff options
Diffstat (limited to 'pose-widget/pose-widget.cpp')
| -rw-r--r-- | pose-widget/pose-widget.cpp | 131 | 
1 files changed, 103 insertions, 28 deletions
| diff --git a/pose-widget/pose-widget.cpp b/pose-widget/pose-widget.cpp index 3ad475cf..c5a6b78e 100644 --- a/pose-widget/pose-widget.cpp +++ b/pose-widget/pose-widget.cpp @@ -13,12 +13,40 @@  #include <QtEvents>  #include <QDebug> -#include <QImage> +#include <QQuaternion> +#include <QMatrix4x4>  namespace pose_widget_impl {  pose_widget::pose_widget(QWidget* parent) : QWidget(parent)  { +    QPainter p; +#ifdef TEST +    //draw rectangle frame around of Octopus, only if TEST defined +    p.begin(&front); +    p.setPen(QPen(Qt::red, 3, Qt::SolidLine)); +    p.drawRect(0, 0, front.width()-1, front.height()-1); +    p.end(); + +    p.begin(&back); +    p.setPen(QPen(Qt::darkGreen, 3, Qt::SolidLine)); +    p.drawRect(0, 0, back.width()-1, back.height()-1); +    p.end(); +#endif + +    //draw Octopus shine +    shine.fill(QColor(255,255,255)); +    p.begin(&shine); +    p.setCompositionMode(QPainter::CompositionMode_DestinationIn); +    p.drawImage(QPointF(0,0), front);		 +    p.end(); + +    //draw Octopus shadow +    shadow.fill(QColor(0,0,0)); +    p.begin(&shadow); +    p.setCompositionMode(QPainter::CompositionMode_DestinationIn); +    p.drawImage(QPointF(0,0), front);		 +    p.end();  }  void pose_widget::present(double yaw, double pitch, double roll, double x, double y, double z) @@ -29,40 +57,87 @@ void pose_widget::present(double yaw, double pitch, double roll, double x, doubl      repaint();  } +void pose_widget::resizeEvent(QResizeEvent *event) +{ +    // adapt to widget size +    float w = event->size().width(); +    float h = event->size().height(); + +    // fill background by color +    constexpr int clr = 220; +    QImage background(QImage(w, h, QImage::Format_ARGB32)); +    background.fill(QColor(clr,clr,clr)); + +    // draw axes +    QPainter p(&background); +    p.setPen(QPen(Qt::gray, 1, Qt::SolidLine)); +    p.drawLine(0.5*w,   0  , 0.5*w,   h  ); +    p.drawLine(  0  , 0.5*h,   w  , 0.5*h); + +    // set AutoFillBackground +    QPalette palette; +    palette.setBrush(this->backgroundRole(), QBrush(background)); +    setPalette(palette); +    setAutoFillBackground(true); + +    // move the mirror checkbox in the lower right corner of the widget +    mirror.setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); +    mirror.move(w - mirror.width(), h - mirror.height()); +} +  void pose_widget::paintEvent(QPaintEvent*)  { +    // widget settings: +    constexpr float scale  =  0.5;   // scale of Octopus height, when x = y = z = 0.0 +    constexpr float XYZmax = 50.0;   // -XYZmax < x,y,z < +XYZmax (offset the Octopus by one body) +    constexpr float Kz     =  0.25;  // Z scale change limit (simulate camera focus length) + +    // get a local copy of input data      auto [ yaw, pitch, roll ] = R;      auto [ x, y, z ] = T; -    const QImage& img = (std::fabs(pitch) > 90) ^ (std::fabs(yaw) > 90) -                        ? back -                        : front; - -    constexpr double scale = .75; -    int w = img.width(), h = iround(img.height()*scale); - -    QTransform t; - -    t.translate(w*.5, h*.5); - -    constexpr double z_scale = 1./250; -    constexpr double xy_scale = .0075; -    double xy = std::sqrt(w*w + h*h) * xy_scale; -    double sx = clamp(.4 + -z * z_scale, .1, 2), sy = sx * 1/scale; - -    t.scale(sx, sy); - -    t.rotate(pitch, Qt::XAxis); -    t.rotate(yaw, Qt::YAxis); -    t.rotate(roll, Qt::ZAxis); - -    t.translate(x * xy / sx, y * xy / sy); - -    t.translate(w*-.5, h*-.5); -      QPainter p(this); +    #ifdef TEST +    // use antialiasing for correct frame around the Octopus, only if TEST defined +    p.setRenderHint(QPainter::Antialiasing, true); +    #endif + +    // check mirror state +    if   (mirror.checkState() == Qt::Checked) x = -x; +    else { yaw = -yaw; roll = -roll; } +    y = -y; + +    // rotations +    QQuaternion q = QQuaternion::fromEulerAngles(pitch,  yaw,  roll); +    QMatrix4x4  m = QMatrix4x4(q.toRotationMatrix()); + +    // x and y positions +    const float Kxy = (float)front.height() / XYZmax; +    QVector3D v(Kxy*x, Kxy*y, 0.0); +    v = m.transposed().map(v); +    m.translate(v); + +    // perspective projection to x-y plane +    QTransform t = m.toTransform(1024).translate(-.5 * front.width(), -.5 * front.height()); + +    // z position by setViewport  +    const float mz = scale * height()/front.height()/exp(1.0) * exp(1.0 - z * (Kz/XYZmax));  +    p.setViewport(QRect(.5 * width(), .5 * height(), width()*mz, height()*mz)); +  +    // define forward or backward side by cross product of mapped x and y axes +    QPointF point0 =  t.map(QPointF(0, 0)); +    QPointF x_dir  = (t.map(QPointF(1, 0)) -= point0); +    QPointF y_dir  = (t.map(QPointF(0, 1)) -= point0); +    const bool  forward  =  x_dir.ry()*y_dir.rx() - x_dir.rx()*y_dir.ry() < 0 ? true : false; + +    // draw red or green Octopus      p.setTransform(t); -    p.drawImage(rect(), img); +    p.drawImage(QPointF(0,0), forward ? front : back); + +    // top lighting simulation +    const float alpha = sin(pitch * M_PI / 180.0); +    p.setOpacity(0.333 * fabs(alpha)); +    p.drawImage(QPointF(0,0), forward == (alpha >= 0.0) ? shine : shadow);  }  QSize pose_widget::sizeHint() const | 
