From e7158125d3c3b63371ddc7dc2d5b7d7865d91e64 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Thu, 30 Mar 2017 13:35:35 +0200 Subject: pose-widget: rename unit and header --- gui/main-window.ui | 2 +- pose-widget/glwidget.cpp | 352 -------------------------------------------- pose-widget/glwidget.h | 95 ------------ pose-widget/pose-widget.cpp | 352 ++++++++++++++++++++++++++++++++++++++++++++ pose-widget/pose-widget.hpp | 95 ++++++++++++ 5 files changed, 448 insertions(+), 448 deletions(-) delete mode 100644 pose-widget/glwidget.cpp delete mode 100644 pose-widget/glwidget.h create mode 100644 pose-widget/pose-widget.cpp create mode 100644 pose-widget/pose-widget.hpp diff --git a/gui/main-window.ui b/gui/main-window.ui index 06375f76..2b1d5671 100644 --- a/gui/main-window.ui +++ b/gui/main-window.ui @@ -1355,7 +1355,7 @@ pose_widget QWidget -
pose-widget/glwidget.h
+
pose-widget/pose-widget.hpp
diff --git a/pose-widget/glwidget.cpp b/pose-widget/glwidget.cpp deleted file mode 100644 index beddc5e9..00000000 --- a/pose-widget/glwidget.cpp +++ /dev/null @@ -1,352 +0,0 @@ -/* Copyright (c) 2013, 2015 Stanislaw Halik - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - */ - -#include "glwidget.h" -#include "compat/util.hpp" -#include "compat/timer.hpp" -#include -#include -#include -#include - -#include - -using namespace pose_widget_impl; - -pose_transform::pose_transform(QWidget* dst) : - dst(dst), - image(w, h, QImage::Format_ARGB32), - image2(w, h, QImage::Format_ARGB32), - width(w), height(h) -{ - front = QImage(QString(":/images/side1.png")); - back = QImage(QString(":/images/side6.png")); - - image.fill(Qt::transparent); - image2.fill(Qt::transparent); - - rotateBy(0, 0, 0, 0, 0, 0, QSize(w, h)); - - project_quad_texture(); - - start(); -} - -pose_transform::~pose_transform() -{ - requestInterruption(); - wait(); -} - -void pose_widget::paintEvent(QPaintEvent* event) -{ - QPainter p(this); - xform.with_image_lock([&](const QImage& image) { - p.drawImage(event->rect(), image); - }); -} - -void pose_transform::run() -{ - for (;;) - { - if (isInterruptionRequested()) - break; - - static struct cruft - { - void lock() {} - void unlock() {} - } not_a_mutex; - - const cv_status st = cvar.wait_for(not_a_mutex, std::chrono::milliseconds(2000)); - if (st == cv_status::timeout) - continue; - - project_quad_texture(); - } -} - -pose_widget::pose_widget(QWidget* parent) : QWidget(parent), xform(this) -{ -} - -pose_widget::~pose_widget() -{ -} - -void pose_widget::rotateBy(double xAngle, double yAngle, double zAngle, double x, double y, double z) -{ - xform.rotateBy(xAngle, yAngle, zAngle, x, y, z, size()); -} - -void pose_transform::rotateBy(double xAngle, double yAngle, double zAngle, double x, double y, double z, const QSize& size) -{ - using std::sin; - using std::cos; - - static constexpr double d2r = M_PI / 180; - - euler::euler_t euler(-zAngle * d2r, xAngle * d2r, -yAngle * d2r); - euler::rmat r = euler::euler_to_rmat(euler); - - lock_guard l(mtx); - - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - rotation(i, j) = num(r(i, j)); - - translation = vec3(x, y, z); - - cvar.notify_one(); -} - -class Triangle { - num dot00, dot01, dot11, invDenom; - vec2 v0, v1, origin; -public: - Triangle(const vec2& p1, const vec2& p2, const vec2& p3); - bool barycentric_coords(const vec2& px, vec2& uv, int& i) const; -}; - -inline vec3 pose_transform::normal(const vec3& p1, const vec3& p2, const vec3& p3) -{ - using std::sqrt; - - vec3 u = p2 - p1; - vec3 v = p3 - p1; - - vec3 tmp = u.cross(v); - - num i = 1/sqrt(tmp.dot(tmp)); - - return tmp * i; -} - -Triangle::Triangle(const vec2& p1, const vec2& p2, const vec2& p3) -{ - using std::fabs; - - origin = p1; - - v0 = vec2(p3 - p1); - v1 = vec2(p2 - p1); - - dot00 = v0.dot(v0); - dot01 = v0.dot(v1); - dot11 = v1.dot(v1); - - const num denom = dot00 * dot11 - dot01 * dot01; - - if (fabs(denom) < num(1e3)) - { - // for perpendicular plane, ensure u and v don't come out right - // this is done here to avoid branching below, in a hot loop - invDenom = 0; - dot00 = dot01 = dot11 = 0; - v0 = v1 = vec2(0, 0); - } - else - invDenom = 1 / denom; -} - -bool Triangle::barycentric_coords(const vec2& px, vec2& uv, int& i) const -{ - i = 0; - const vec2 v2 = px - origin; - const num dot12 = v1.dot(v2); - const num dot02 = v0.dot(v2); - num u = (dot11 * dot02 - dot01 * dot12) * invDenom; - num v = (dot00 * dot12 - dot01 * dot02) * invDenom; - if (!(u >= 0 && v >= 0)) - return false; - if (u + v > 1) - { - i = 1; - - u = 1 - u; - v = 1 - v; - } - uv = vec2(u, v); - return u >= 0 && v >= 0 && u + v <= 1; -} - -void pose_transform::project_quad_texture() -{ - num dir; - vec2 pt[4]; - const int sx = width - 1, sy = height - 1; - vec2 projected[3]; - - lock_guard l(mtx); - - { - const int sx_ = (sx - std::max(0, (sx - sy)/2)) * 5/9; - const int sy_ = (sy - std::max(0, (sy - sx)/2)) * 5/9; - - static constexpr const double c = 85/100.; - - const vec3 dst_corners[] = - { - vec3(-sx_/2. * c, -sy_/2., 0), - vec3(sx_/2. * c, -sy_/2., 0), - vec3(-sx_/2. * c, sy_/2., 0), - vec3(sx_/2. * c, sy_/2., 0.) - }; - - for (int i = 0; i < 4; i++) - pt[i] = project(dst_corners[i]) + vec2(sx/2, sy/2); - - vec3 normal1(0, 0, 1); - vec3 normal2; - { - vec3 foo[3]; - for (int i = 0; i < 3; i++) - { - foo[i] = project2(dst_corners[i]); - projected[i] = project(dst_corners[i]) + vec2(sx/2, sy/2); - } - normal2 = normal(foo[0], foo[1], foo[2]); - } - dir = normal1.dot(normal2); - } - - const QImage& tex = dir < 0 ? back : front; - const int ow = tex.width(), oh = tex.height(); - - vec2 origs[2][3] = - { - { - vec2(0, 0), - vec2(ow-1, 0), - vec2(0, oh-1) - }, - { - vec2(ow-1, oh-1), - vec2(0, oh-1) - vec2(ow-1, oh-1), - vec2(ow-1, 0) - vec2(ow-1, oh-1), - } - }; - - Triangle t(projected[0], projected[1], projected[2]); - - const int orig_pitch = tex.bytesPerLine(); - const int dest_pitch = image.bytesPerLine(); - - const unsigned char* orig = tex.bits(); - unsigned char* dest = image.bits(); - - const int orig_depth = tex.depth() / 8; - const int dest_depth = image.depth() / 8; - - /* image breakage? */ - if (orig_depth != 4) - { - qDebug() << "pose-widget: octopus must be saved as .png with 32-bit depth"; - return; - } - - const vec3 half = rotation * vec3(.5f, .5f, 0); - - for (int y = 1; y < sy; y++) - for (int x = 1; x < sx; x++) - { - vec2 pos(x, y); - vec2 uv; - int i; - if (t.barycentric_coords(pos, uv, i)) - { - const float fx = origs[i][0].x() - + uv.x() * origs[i][2].x() - + uv.y() * origs[i][1].x(); - const float fy = origs[i][0].y() - + uv.x() * origs[i][2].y() - + uv.y() * origs[i][1].y(); - - const int px_ = fx + half.x(); - const int py_ = fy + half.y(); - const int px = fx; - const int py = fy; - const float ax_ = fx - px; - const float ay_ = fy - py; - const float ax = 1 - ax_; - const float ay = 1 - ay_; - - // 0, 0 -- ax, ay - const int orig_pos = py * orig_pitch + px * orig_depth; - const unsigned char r = orig[orig_pos + 2]; - const unsigned char g = orig[orig_pos + 1]; - const unsigned char b = orig[orig_pos + 0]; - - // 1, 1 -- ax_, ay_ - const int orig_pos_ = py_ * orig_pitch + px_ * orig_depth; - const unsigned char r_ = orig[orig_pos_ + 2]; - const unsigned char g_ = orig[orig_pos_ + 1]; - const unsigned char b_ = orig[orig_pos_ + 0]; - - // 1, 0 -- ax_, ay - const int orig_pos__ = py * orig_pitch + px_ * orig_depth; - const unsigned char r__ = orig[orig_pos__ + 2]; - const unsigned char g__ = orig[orig_pos__ + 1]; - const unsigned char b__ = orig[orig_pos__ + 0]; - - // 0, 1 -- ax, ay_ - const int orig_pos___ = py_ * orig_pitch + px * orig_depth; - const unsigned char r___ = orig[orig_pos___ + 2]; - const unsigned char g___ = orig[orig_pos___ + 1]; - const unsigned char b___ = orig[orig_pos___ + 0]; - - const unsigned char a1 = orig[orig_pos + 3]; - const unsigned char a2 = orig[orig_pos_ + 3]; - const unsigned char a3 = orig[orig_pos__ + 3]; - const unsigned char a4 = orig[orig_pos___ + 3]; - - const int pos = y * dest_pitch + x * dest_depth; - - dest[pos + 2] = (r * ax + r__ * ax_) * ay + (r___ * ax + r_ * ax_) * ay_; - dest[pos + 1] = (g * ax + g__ * ax_) * ay + (g___ * ax + g_ * ax_) * ay_; - dest[pos + 0] = (b * ax + b__ * ax_) * ay + (b___ * ax + b_ * ax_) * ay_; - dest[pos + 3] = (a1 * ax + a3 * ax_) * ay + (a4 * ax + a2 * ax_) * ay_; - } - } - - { - lock_guard l2(mtx2); - image2.fill(Qt::transparent); - std::swap(image, image2); - } - - run_in_thread_async(dst->thread(), [this]() { dst->update(); }); -} - -vec2 pose_transform::project(const vec3 &point) -{ - vec3 ret = rotation * point; - num z = std::max(.75f, 1 + translation.z()/-60); - num w = width, h = height; - num x = w * translation.x() / 2 / -40; - if (std::abs(x) > w/2) - x = x > 0 ? w/2 : w/-2; - num y = h * translation.y() / 2 / -40; - if (std::abs(y) > h/2) - y = y > 0 ? h/2 : h/-2; - return vec2(z * (ret.x() + x), z * (ret.y() + y)); -} - -vec3 pose_transform::project2(const vec3 &point) -{ - return rotation * point; -} - - -template -inline void pose_transform::with_image_lock(F&& fun) -{ - lock_guard l(mtx2); - - fun(image2); -} diff --git a/pose-widget/glwidget.h b/pose-widget/glwidget.h deleted file mode 100644 index 4f50008e..00000000 --- a/pose-widget/glwidget.h +++ /dev/null @@ -1,95 +0,0 @@ -/* Copyright (c) 2013, 2015 Stanislaw Halik - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - */ - -#pragma once - -#include -#include -#include -#include -#include "api/plugin-api.hpp" -#include "compat/euler.hpp" - -#include -#include - -#ifdef BUILD_POSE_WIDGET -# define POSE_WIDGET_EXPORT Q_DECL_EXPORT -#else -# define POSE_WIDGET_EXPORT Q_DECL_IMPORT -#endif - -namespace pose_widget_impl { - -using num = float; -using vec3 = Mat; -using vec2 = Mat; - -using rmat = Mat; - -using namespace euler; - -using lock_guard = std::unique_lock; - -using cv_status = std::cv_status; - -class pose_widget; - -class pose_transform final : private QThread -{ - pose_transform(QWidget* dst); - ~pose_transform(); - - friend class pose_widget; - - void rotateBy(double xAngle, double yAngle, double zAngle, - double x, double y, double z, - const QSize& size); - - void run() override; - - vec2 project(const vec3& point); - vec3 project2(const vec3& point); - void project_quad_texture(); - - template - inline void with_image_lock(F&& fun); - - static vec3 normal(const vec3& p1, const vec3& p2, const vec3& p3); - - rmat rotation; - vec3 translation; - - std::condition_variable_any cvar; - std::mutex mtx, mtx2; - - QWidget* dst; - - QImage front, back; - QImage image, image2; - - int width, height; - - static constexpr int w = 320, h = 240; -}; - -class POSE_WIDGET_EXPORT pose_widget final : public QWidget -{ -public: - pose_widget(QWidget *parent = nullptr); - ~pose_widget(); - void rotateBy(double xAngle, double yAngle, double zAngle, - double x, double y, double z); - -private: - pose_transform xform; - void paintEvent(QPaintEvent *event) override; -}; - -} - -using pose_widget_impl::pose_widget; diff --git a/pose-widget/pose-widget.cpp b/pose-widget/pose-widget.cpp new file mode 100644 index 00000000..a0653f17 --- /dev/null +++ b/pose-widget/pose-widget.cpp @@ -0,0 +1,352 @@ +/* Copyright (c) 2013, 2015 Stanislaw Halik + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#include "pose-widget.hpp" +#include "compat/util.hpp" +#include "compat/timer.hpp" +#include +#include +#include +#include + +#include + +using namespace pose_widget_impl; + +pose_transform::pose_transform(QWidget* dst) : + dst(dst), + image(w, h, QImage::Format_ARGB32), + image2(w, h, QImage::Format_ARGB32), + width(w), height(h) +{ + front = QImage(QString(":/images/side1.png")); + back = QImage(QString(":/images/side6.png")); + + image.fill(Qt::transparent); + image2.fill(Qt::transparent); + + rotateBy(0, 0, 0, 0, 0, 0, QSize(w, h)); + + project_quad_texture(); + + start(); +} + +pose_transform::~pose_transform() +{ + requestInterruption(); + wait(); +} + +void pose_widget::paintEvent(QPaintEvent* event) +{ + QPainter p(this); + xform.with_image_lock([&](const QImage& image) { + p.drawImage(event->rect(), image); + }); +} + +void pose_transform::run() +{ + for (;;) + { + if (isInterruptionRequested()) + break; + + static struct cruft + { + void lock() {} + void unlock() {} + } not_a_mutex; + + const cv_status st = cvar.wait_for(not_a_mutex, std::chrono::milliseconds(2000)); + if (st == cv_status::timeout) + continue; + + project_quad_texture(); + } +} + +pose_widget::pose_widget(QWidget* parent) : QWidget(parent), xform(this) +{ +} + +pose_widget::~pose_widget() +{ +} + +void pose_widget::rotateBy(double xAngle, double yAngle, double zAngle, double x, double y, double z) +{ + xform.rotateBy(xAngle, yAngle, zAngle, x, y, z, size()); +} + +void pose_transform::rotateBy(double xAngle, double yAngle, double zAngle, double x, double y, double z, const QSize& size) +{ + using std::sin; + using std::cos; + + static constexpr double d2r = M_PI / 180; + + euler::euler_t euler(-zAngle * d2r, xAngle * d2r, -yAngle * d2r); + euler::rmat r = euler::euler_to_rmat(euler); + + lock_guard l(mtx); + + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + rotation(i, j) = num(r(i, j)); + + translation = vec3(x, y, z); + + cvar.notify_one(); +} + +class Triangle { + num dot00, dot01, dot11, invDenom; + vec2 v0, v1, origin; +public: + Triangle(const vec2& p1, const vec2& p2, const vec2& p3); + bool barycentric_coords(const vec2& px, vec2& uv, int& i) const; +}; + +inline vec3 pose_transform::normal(const vec3& p1, const vec3& p2, const vec3& p3) +{ + using std::sqrt; + + vec3 u = p2 - p1; + vec3 v = p3 - p1; + + vec3 tmp = u.cross(v); + + num i = 1/sqrt(tmp.dot(tmp)); + + return tmp * i; +} + +Triangle::Triangle(const vec2& p1, const vec2& p2, const vec2& p3) +{ + using std::fabs; + + origin = p1; + + v0 = vec2(p3 - p1); + v1 = vec2(p2 - p1); + + dot00 = v0.dot(v0); + dot01 = v0.dot(v1); + dot11 = v1.dot(v1); + + const num denom = dot00 * dot11 - dot01 * dot01; + + if (fabs(denom) < num(1e3)) + { + // for perpendicular plane, ensure u and v don't come out right + // this is done here to avoid branching below, in a hot loop + invDenom = 0; + dot00 = dot01 = dot11 = 0; + v0 = v1 = vec2(0, 0); + } + else + invDenom = 1 / denom; +} + +bool Triangle::barycentric_coords(const vec2& px, vec2& uv, int& i) const +{ + i = 0; + const vec2 v2 = px - origin; + const num dot12 = v1.dot(v2); + const num dot02 = v0.dot(v2); + num u = (dot11 * dot02 - dot01 * dot12) * invDenom; + num v = (dot00 * dot12 - dot01 * dot02) * invDenom; + if (!(u >= 0 && v >= 0)) + return false; + if (u + v > 1) + { + i = 1; + + u = 1 - u; + v = 1 - v; + } + uv = vec2(u, v); + return u >= 0 && v >= 0 && u + v <= 1; +} + +void pose_transform::project_quad_texture() +{ + num dir; + vec2 pt[4]; + const int sx = width - 1, sy = height - 1; + vec2 projected[3]; + + lock_guard l(mtx); + + { + const int sx_ = (sx - std::max(0, (sx - sy)/2)) * 5/9; + const int sy_ = (sy - std::max(0, (sy - sx)/2)) * 5/9; + + static constexpr const double c = 85/100.; + + const vec3 dst_corners[] = + { + vec3(-sx_/2. * c, -sy_/2., 0), + vec3(sx_/2. * c, -sy_/2., 0), + vec3(-sx_/2. * c, sy_/2., 0), + vec3(sx_/2. * c, sy_/2., 0.) + }; + + for (int i = 0; i < 4; i++) + pt[i] = project(dst_corners[i]) + vec2(sx/2, sy/2); + + vec3 normal1(0, 0, 1); + vec3 normal2; + { + vec3 foo[3]; + for (int i = 0; i < 3; i++) + { + foo[i] = project2(dst_corners[i]); + projected[i] = project(dst_corners[i]) + vec2(sx/2, sy/2); + } + normal2 = normal(foo[0], foo[1], foo[2]); + } + dir = normal1.dot(normal2); + } + + const QImage& tex = dir < 0 ? back : front; + const int ow = tex.width(), oh = tex.height(); + + vec2 origs[2][3] = + { + { + vec2(0, 0), + vec2(ow-1, 0), + vec2(0, oh-1) + }, + { + vec2(ow-1, oh-1), + vec2(0, oh-1) - vec2(ow-1, oh-1), + vec2(ow-1, 0) - vec2(ow-1, oh-1), + } + }; + + Triangle t(projected[0], projected[1], projected[2]); + + const int orig_pitch = tex.bytesPerLine(); + const int dest_pitch = image.bytesPerLine(); + + const unsigned char* orig = tex.bits(); + unsigned char* dest = image.bits(); + + const int orig_depth = tex.depth() / 8; + const int dest_depth = image.depth() / 8; + + /* image breakage? */ + if (orig_depth != 4) + { + qDebug() << "pose-widget: octopus must be saved as .png with 32-bit depth"; + return; + } + + const vec3 half = rotation * vec3(.5f, .5f, 0); + + for (int y = 1; y < sy; y++) + for (int x = 1; x < sx; x++) + { + vec2 pos(x, y); + vec2 uv; + int i; + if (t.barycentric_coords(pos, uv, i)) + { + const float fx = origs[i][0].x() + + uv.x() * origs[i][2].x() + + uv.y() * origs[i][1].x(); + const float fy = origs[i][0].y() + + uv.x() * origs[i][2].y() + + uv.y() * origs[i][1].y(); + + const int px_ = fx + half.x(); + const int py_ = fy + half.y(); + const int px = fx; + const int py = fy; + const float ax_ = fx - px; + const float ay_ = fy - py; + const float ax = 1 - ax_; + const float ay = 1 - ay_; + + // 0, 0 -- ax, ay + const int orig_pos = py * orig_pitch + px * orig_depth; + const unsigned char r = orig[orig_pos + 2]; + const unsigned char g = orig[orig_pos + 1]; + const unsigned char b = orig[orig_pos + 0]; + + // 1, 1 -- ax_, ay_ + const int orig_pos_ = py_ * orig_pitch + px_ * orig_depth; + const unsigned char r_ = orig[orig_pos_ + 2]; + const unsigned char g_ = orig[orig_pos_ + 1]; + const unsigned char b_ = orig[orig_pos_ + 0]; + + // 1, 0 -- ax_, ay + const int orig_pos__ = py * orig_pitch + px_ * orig_depth; + const unsigned char r__ = orig[orig_pos__ + 2]; + const unsigned char g__ = orig[orig_pos__ + 1]; + const unsigned char b__ = orig[orig_pos__ + 0]; + + // 0, 1 -- ax, ay_ + const int orig_pos___ = py_ * orig_pitch + px * orig_depth; + const unsigned char r___ = orig[orig_pos___ + 2]; + const unsigned char g___ = orig[orig_pos___ + 1]; + const unsigned char b___ = orig[orig_pos___ + 0]; + + const unsigned char a1 = orig[orig_pos + 3]; + const unsigned char a2 = orig[orig_pos_ + 3]; + const unsigned char a3 = orig[orig_pos__ + 3]; + const unsigned char a4 = orig[orig_pos___ + 3]; + + const int pos = y * dest_pitch + x * dest_depth; + + dest[pos + 2] = (r * ax + r__ * ax_) * ay + (r___ * ax + r_ * ax_) * ay_; + dest[pos + 1] = (g * ax + g__ * ax_) * ay + (g___ * ax + g_ * ax_) * ay_; + dest[pos + 0] = (b * ax + b__ * ax_) * ay + (b___ * ax + b_ * ax_) * ay_; + dest[pos + 3] = (a1 * ax + a3 * ax_) * ay + (a4 * ax + a2 * ax_) * ay_; + } + } + + { + lock_guard l2(mtx2); + image2.fill(Qt::transparent); + std::swap(image, image2); + } + + run_in_thread_async(dst->thread(), [this]() { dst->update(); }); +} + +vec2 pose_transform::project(const vec3 &point) +{ + vec3 ret = rotation * point; + num z = std::max(.75f, 1 + translation.z()/-60); + num w = width, h = height; + num x = w * translation.x() / 2 / -40; + if (std::abs(x) > w/2) + x = x > 0 ? w/2 : w/-2; + num y = h * translation.y() / 2 / -40; + if (std::abs(y) > h/2) + y = y > 0 ? h/2 : h/-2; + return vec2(z * (ret.x() + x), z * (ret.y() + y)); +} + +vec3 pose_transform::project2(const vec3 &point) +{ + return rotation * point; +} + + +template +inline void pose_transform::with_image_lock(F&& fun) +{ + lock_guard l(mtx2); + + fun(image2); +} diff --git a/pose-widget/pose-widget.hpp b/pose-widget/pose-widget.hpp new file mode 100644 index 00000000..4f50008e --- /dev/null +++ b/pose-widget/pose-widget.hpp @@ -0,0 +1,95 @@ +/* Copyright (c) 2013, 2015 Stanislaw Halik + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#pragma once + +#include +#include +#include +#include +#include "api/plugin-api.hpp" +#include "compat/euler.hpp" + +#include +#include + +#ifdef BUILD_POSE_WIDGET +# define POSE_WIDGET_EXPORT Q_DECL_EXPORT +#else +# define POSE_WIDGET_EXPORT Q_DECL_IMPORT +#endif + +namespace pose_widget_impl { + +using num = float; +using vec3 = Mat; +using vec2 = Mat; + +using rmat = Mat; + +using namespace euler; + +using lock_guard = std::unique_lock; + +using cv_status = std::cv_status; + +class pose_widget; + +class pose_transform final : private QThread +{ + pose_transform(QWidget* dst); + ~pose_transform(); + + friend class pose_widget; + + void rotateBy(double xAngle, double yAngle, double zAngle, + double x, double y, double z, + const QSize& size); + + void run() override; + + vec2 project(const vec3& point); + vec3 project2(const vec3& point); + void project_quad_texture(); + + template + inline void with_image_lock(F&& fun); + + static vec3 normal(const vec3& p1, const vec3& p2, const vec3& p3); + + rmat rotation; + vec3 translation; + + std::condition_variable_any cvar; + std::mutex mtx, mtx2; + + QWidget* dst; + + QImage front, back; + QImage image, image2; + + int width, height; + + static constexpr int w = 320, h = 240; +}; + +class POSE_WIDGET_EXPORT pose_widget final : public QWidget +{ +public: + pose_widget(QWidget *parent = nullptr); + ~pose_widget(); + void rotateBy(double xAngle, double yAngle, double zAngle, + double x, double y, double z); + +private: + pose_transform xform; + void paintEvent(QPaintEvent *event) override; +}; + +} + +using pose_widget_impl::pose_widget; -- cgit v1.2.3