diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2018-02-05 09:33:00 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2018-02-16 19:15:47 +0100 |
commit | 664f9c94fbb570f0b5abae1b36c5940275813096 (patch) | |
tree | ab4b62edf3521ee0a6fe2cbad716dcb5d867c1cf | |
parent | b52fd95f1cc86e86ecb696eab07c8d6b6a2e9f5d (diff) |
logic/pipeline: simplify
The pipeline code is hard to understand for programmers due to the
practice of putting all logic into a single function.
Split it up into logical components.
This needs more testing and bug reports. It's a big change with possibly
many regressions all over the place.
Issue: #688
-rw-r--r-- | logic/pipeline.cpp | 435 | ||||
-rw-r--r-- | logic/pipeline.hpp | 28 | ||||
-rw-r--r-- | logic/work.cpp | 12 |
3 files changed, 261 insertions, 214 deletions
diff --git a/logic/pipeline.cpp b/logic/pipeline.cpp index 9059a251..654a9f09 100644 --- a/logic/pipeline.cpp +++ b/logic/pipeline.cpp @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015 Stanislaw Halik <sthalik@misaki.pl> +/* Copyright (c) 2012-2018 Stanislaw Halik <sthalik@misaki.pl> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -35,40 +35,39 @@ static constexpr inline double d2r = M_PI / 180.; reltrans::reltrans() {} -euler_t reltrans::rotate(const rmat& rmat, const euler_t& xyz, - bool disable_tx, bool disable_ty, bool disable_tz) const +euler_t reltrans::rotate(const rmat& R, const euler_t& in, vec3_bool disable) const { enum { tb_Z, tb_X, tb_Y }; // TY is really yaw axis. need swapping accordingly. // sign changes are due to right-vs-left handedness of coordinate system used - const euler_t ret = rmat * euler_t(xyz(TZ), -xyz(TX), -xyz(TY)); + const euler_t ret = R * euler_t(in(TZ), -in(TX), -in(TY)); euler_t output; - if (disable_tz) - output(TZ) = xyz(TZ); + if (disable(TZ)) + output(TZ) = in(TZ); else output(TZ) = ret(tb_Z); - if (disable_ty) - output(TY) = xyz(TY); + if (disable(TY)) + output(TY) = in(TY); else output(TY) = -ret(tb_Y); - if (disable_tx) - output(TX) = xyz(TX); + if (disable(TX)) + output(TX) = in(TX); else output(TX) = -ret(tb_X); return output; } -Pose reltrans::apply_pipeline(reltrans_state state, const Pose& value, const Mat<bool, 6, 1>& disable) +Pose reltrans::apply_pipeline(reltrans_state state, const Pose& value, const vec6_bool& disable) { if (state != reltrans_disabled) { - euler_t rel { value(TX), value(TY), value(TZ) }; + euler_t rel { &value[0] }; { bool tcomp_in_zone_ = progn( @@ -96,21 +95,11 @@ Pose reltrans::apply_pipeline(reltrans_state state, const Pose& value, const Mat // only when looking behind or downward if (in_zone) { - const double tcomp_c[] = { - double(!disable(Yaw)), - double(!disable(Pitch)), - double(!disable(Roll)), - }; - - const rmat R = euler_to_rmat(euler_t(value(Yaw) * d2r * tcomp_c[0], - value(Pitch) * d2r * tcomp_c[1], - value(Roll) * d2r * tcomp_c[2])); - - rel = rotate(R, - rel, - disable(TX), - disable(TY), - disable(TZ)); + const rmat R = euler_to_rmat(euler_t(value(Yaw) * d2r * !disable(Yaw), + value(Pitch) * d2r * !disable(Pitch), + value(Roll) * d2r * !disable(Roll))); + + rel = rotate(R, rel, &disable[TX]); } if (cur) @@ -153,6 +142,23 @@ Pose reltrans::apply_pipeline(reltrans_state state, const Pose& value, const Mat } } +euler_t reltrans::apply_neck(const Pose& value, bool enable, int nz) const +{ + if (!enable) + return {}; + + euler_t neck; + + if (nz != 0) + { + const rmat R = euler_to_rmat(euler_t(&value[Yaw]) * d2r); + neck = rotate(R, { 0, 0, nz }, vec3_bool()); + neck(TZ) = neck(TZ) - nz; + } + + return neck; +} + pipeline::pipeline(Mappings& m, runtime_libraries& libs, event_handler& ev, TrackLogger& logger) : m(m), ev(ev), @@ -191,78 +197,104 @@ static bool is_nan(const dmat<u,w>& r) } template<typename x, typename y, typename... xs> -static inline bool nan_check_(const x& datum, const y& next, const xs&... rest) +static force_inline bool nan_check_(const x& datum, const y& next, const xs&... rest) { - return !is_nan(datum) && nan_check_(next, rest...); + return is_nan(datum) || nan_check_(next, rest...); } template<typename x> -static inline bool nan_check_(const x& datum) +static force_inline bool nan_check_(const x& datum) { - return !is_nan(datum); + return is_nan(datum); } template<typename> static bool nan_check_() = delete; static never_inline -void emit_nan_check_msg(const char* text, int line) +void emit_nan_check_msg(const char* text, const char* fun, int line) { - once_only(qDebug() << "nan check failed" - << "line:" << text - << "for:" << line); + once_only( + qDebug() << "nan check failed" + << "for:" << text + << "function:" << fun + << "line:" << line; + ); } -#define nan_check(...) \ - do \ - { \ - if (!nan_check_(__VA_ARGS__)) \ - { \ - emit_nan_check_msg(#__VA_ARGS__, __LINE__); \ - goto nan; \ - } \ - } while (false) - -void pipeline::logic() +template<typename... xs> +static never_inline +bool maybe_nan(const char* text, const char* fun, int line, const xs&... vals) { - using namespace euler; - using EV = event_handler::event_ordinal; - - logger.write_dt(); - logger.reset_dt(); - - // we must center prior to getting data - const bool center_ordered = get(f_center) && tracking_started; - set(f_center, false); - const bool own_center_logic = center_ordered && libs.pTracker->center(); + if (nan_check_(vals...)) + { + emit_nan_check_msg(text, fun, line); + return true; + } + return false; +} - Pose value, raw; +#if defined _MSC_VER +# define OTR_FUNNAME2 (__FUNCSIG__) +#else +# define OTR_FUNNAME2 (__PRETTY_FUNCTION__) +#endif +// don't expand +# define OTR_FUNNAME (OTR_FUNNAME2) + +#define nan_check(...) \ + do \ + { \ + if (maybe_nan(#__VA_ARGS__, OTR_FUNNAME, __LINE__, __VA_ARGS__)) \ + goto nan; \ + } while (false) +void pipeline::maybe_enable_center_on_tracking_started() +{ + if (!tracking_started) { - Pose tmp; - libs.pTracker->data(tmp); - nan_check(tmp); - ev.run_events(EV::ev_raw, tmp); + for (int i = 0; i < 6; i++) + if (std::fabs(newpose(i)) != 0) + { + tracking_started = true; + break; + } - if (get(f_enabled_p) ^ !get(f_enabled_h)) - for (int i = 0; i < 6; i++) - newpose(i) = tmp(i); + if (tracking_started && s.center_at_startup) + set(f_center, true); } +} - bool disabled[6]; +void pipeline::maybe_set_center_pose(const Pose& value, bool own_center_logic) +{ + euler_t tmp = d2r * euler_t(&value[Yaw]); + scaled_rotation.rotation = euler_to_rmat(c_div * tmp); + real_rotation.rotation = euler_to_rmat(tmp); - for (int i = 0; i < 6; i++) + if (get(f_center)) { - auto& axis = m(i); - int k = axis.opts.src; - disabled[i] = k == 6; - if (k < 0 || k >= 6) - value(i) = 0; + if (libs.pFilter) + libs.pFilter->center(); + + if (own_center_logic) + { + scaled_rotation.rot_center = rmat::eye(); + real_rotation.rot_center = rmat::eye(); + + t_center = euler_t(); + } else - value(i) = newpose(k); - raw(i) = newpose(i); + { + real_rotation.rot_center = real_rotation.rotation.t(); + scaled_rotation.rot_center = scaled_rotation.rotation.t(); + + t_center = euler_t(static_cast<const double*>(value)); + } } +} +Pose pipeline::clamp_value(Pose value) const +{ // hatire, udp, and freepie trackers can mess up here for (unsigned i = 3; i < 6; i++) { @@ -279,159 +311,162 @@ void pipeline::logic() value(i) = clamp(x, -180, 180); } - logger.write_pose(raw); // raw + return value; +} - // TODO split this function, it's too big +Pose pipeline::apply_center(Pose value) const +{ + rmat rotation = scaled_rotation.rotation * scaled_rotation.rot_center; + euler_t pos = euler_t(value) - t_center; + euler_t rot = r2d * c_mult * rmat_to_euler(rotation); + + pos = rel.rotate(real_rotation.rot_center, pos, vec3_bool()); + for (int i = 0; i < 3; i++) { - euler_t tmp = d2r * euler_t(&value[Yaw]); - scaled_rotation.rotation = euler_to_rmat(c_div * tmp); - real_rotation.rotation = euler_to_rmat(tmp); + // don't invert after t_compensate + // inverting here doesn't break centering + + if (m(i+3).opts.invert) + rot(i) = -rot(i); + if (m(i).opts.invert) + pos(i) = -pos(i); } - if (!tracking_started) + for (int i = 0; i < 3; i++) { - for (int i = 0; i < 6; i++) - if (std::fabs(newpose(i)) != 0) - { - tracking_started = true; - break; - } - - if (tracking_started && s.center_at_startup) - { - set(f_center, true); - } + value(i) = pos(i); + value(i+3) = rot(i); } - if (center_ordered) + return value; +} + +std::tuple<Pose, Pose, vec6_bool> +pipeline::get_selected_axis_value(const Pose& newpose) const +{ + Pose value; + vec6_bool disabled; + + for (int i = 0; i < 6; i++) { - if (libs.pFilter) - libs.pFilter->center(); + const Map& axis = m(i); + const int k = axis.opts.src; - if (own_center_logic) - { - scaled_rotation.rot_center = rmat::eye(); - real_rotation.rot_center = rmat::eye(); + disabled(i) = k == 6; - t_center = euler_t(); - } + if (k < 0 || k >= 6) + value(i) = 0; else - { - real_rotation.rot_center = real_rotation.rotation.t(); - scaled_rotation.rot_center = scaled_rotation.rotation.t(); - - t_center = euler_t(&value(TX)); - } + value(i) = newpose(k); } - { - rmat rotation = scaled_rotation.rotation; - euler_t pos = euler_t(&value[TX]) - t_center; + return { newpose, value, disabled }; +} - //switch (s.center_method) - switch (1) - { - case 0: - // inertial - rotation = scaled_rotation.rot_center * rotation; - break; - - default: - case 1: - // camera - rotation = rotation * scaled_rotation.rot_center; - pos = rel.rotate(real_rotation.rot_center, pos, false, false, false); - break; - } +Pose pipeline::maybe_apply_filter(const Pose& value) const +{ + Pose tmp(value); - euler_t rot = r2d * c_mult * rmat_to_euler(rotation); + // nan/inf values will corrupt filter internal state + if (libs.pFilter) + libs.pFilter->filter(value, tmp); - for (int i = 0; i < 3; i++) - { - // don't invert after t_compensate - // inverting here doesn't break centering + return tmp; +} - if (m(i+3).opts.invert) - rot(i) = -rot(i); - if (m(i).opts.invert) - pos(i) = -pos(i); - } +Pose pipeline::apply_zero_pos(Pose value) const +{ + // custom zero position + for (int i = 0; i < 6; i++) + value(i) += m(i).opts.zero * (m(i).opts.invert ? -1 : 1); - for (int i = 0; i < 3; i++) - { - value(i) = pos(i); - value(i+3) = rot(i); - } - } + return value; +} - logger.write_pose(value); // "corrected" - after various transformations to account for camera position +Pose pipeline::apply_reltrans(Pose value, vec6_bool disabled) +{ + const euler_t neck = rel.apply_neck(value, s.neck_enable, -s.neck_z); - ev.run_events(EV::ev_before_filter, value); + value = rel.apply_pipeline(s.reltrans_mode, value, + { !!s.reltrans_disable_src_yaw, + !!s.reltrans_disable_src_pitch, + !!s.reltrans_disable_src_roll, + !!s.reltrans_disable_tx, + !!s.reltrans_disable_ty, + !!s.reltrans_disable_tz }); - { - { - Pose tmp(value); + for (int i = 0; i < 3; i++) + value(i) += neck(i); - // nan/inf values will corrupt filter internal state - if (libs.pFilter) - libs.pFilter->filter(tmp, value); + // reltrans will move it + for (unsigned k = 0; k < 6; k++) + if (disabled(k)) + value(k) = 0; - nan_check(value); + return value; +} - logger.write_pose(value); // "filtered" - } - } +void pipeline::logic() +{ + using namespace euler; + using EV = event_handler::event_ordinal; - { - ev.run_events(EV::ev_before_mapping, value); + logger.write_dt(); + logger.reset_dt(); - { - euler_t neck; + // we must center prior to getting data from the tracker + const bool center_ordered = get(f_center) && tracking_started; + const bool own_center_logic = center_ordered && libs.pTracker->center(); - if (s.neck_enable) - { - double nz = -s.neck_z; + Pose value, raw; + vec6_bool disabled; - if (nz != 0) - { - const rmat R = euler_to_rmat( - euler_t(value(Yaw) * d2r, - value(Pitch) * d2r, - value(Roll) * d2r)); - neck = rel.rotate(R, { 0, 0, nz }, false, false, false); - neck(TZ) = neck(TZ) - nz; - - nan_check(neck); - } - } + { + Pose tmp; + libs.pTracker->data(tmp); + nan_check(tmp); + ev.run_events(EV::ev_raw, tmp); + + if (get(f_enabled_p) ^ !get(f_enabled_h)) + for (int i = 0; i < 6; i++) + newpose(i) = tmp(i); + } - // CAVEAT rotation only, due to tcomp - for (int i = 3; i < 6; i++) - value(i) = map(value(i), m(i)); + std::tie(raw, value, disabled) = get_selected_axis_value(newpose); + logger.write_pose(raw); // raw - nan_check(value); + value = clamp_value(value); - value = rel.apply_pipeline(s.reltrans_mode, value, { - !!s.reltrans_disable_src_yaw, !!s.reltrans_disable_src_pitch, !!s.reltrans_disable_src_roll, - !!s.reltrans_disable_tx, !!s.reltrans_disable_ty, !!s.reltrans_disable_tz - }); + { + maybe_enable_center_on_tracking_started(); + maybe_set_center_pose(value, own_center_logic); + value = apply_center(value); + logger.write_pose(value); // "corrected" - after various transformations to account for camera position + } - for (int i = 0; i < 3; i++) - value(i) += neck(i); - } + { + ev.run_events(EV::ev_before_filter, value); + value = maybe_apply_filter(value); + nan_check(value); + logger.write_pose(value); // "filtered" + } - // relative translation can move it - for (unsigned k = 0; k < 6; k++) - if (disabled[k]) - value(k) = 0; + { + ev.run_events(EV::ev_before_mapping, value); + // CAVEAT rotation only, due to tcomp + for (int i = 3; i < 6; i++) + value(i) = map(value(i), m(i)); } - // CAVEAT translation only, due to tcomp - for (int i = 0; i < 3; i++) - value(i) = map(value(i), m(i)); + value = apply_reltrans(value, disabled); - nan_check(value); + { + // CAVEAT translation only, due to tcomp + for (int i = 0; i < 3; i++) + value(i) = map(value(i), m(i)); + nan_check(value); + } goto ok; @@ -444,21 +479,20 @@ nan: // for widget last value display for (int i = 0; i < 6; i++) - (void) map(raw_6dof(i), m(i)); + (void)map(raw_6dof(i), m(i)); } ok: + set(f_center, false); + if (get(f_zero)) for (int i = 0; i < 6; i++) value(i) = 0; - // custom zero position - for (int i = 0; i < 6; i++) - value(i) += m(i).opts.zero * (m(i).opts.invert ? -1 : 1); + value = apply_zero_pos(value); ev.run_events(EV::ev_finished, value); - libs.pProtocol->pose(value); QMutexLocker foo(&mtx); @@ -553,16 +587,15 @@ void pipeline::raw_and_mapped_pose(double* mapped, double* raw) const } } -void pipeline::center() { set(f_center, true); } +void pipeline::set_center() { set(f_center, true); } -void pipeline::set_toggle(bool value) { set(f_enabled_h, value); } +void pipeline::set_enabled(bool value) { set(f_enabled_h, value); } void pipeline::set_zero(bool value) { set(f_zero, value); } -void pipeline::zero() { negate(f_zero); } +void pipeline::toggle_zero() { negate(f_zero); } void pipeline::toggle_enabled() { negate(f_enabled_p); } - -void bits::set(bits::flags flag_, bool val_) +void bits::set(flags flag_, bool val_) { const unsigned flag = unsigned(flag_); const unsigned val = unsigned(val_); @@ -578,7 +611,7 @@ void bits::set(bits::flags flag_, bool val_) } } -void bits::negate(bits::flags flag_) +void bits::negate(flags flag_) { const unsigned flag = unsigned(flag_); @@ -594,7 +627,7 @@ void bits::negate(bits::flags flag_) } } -bool bits::get(bits::flags flag) +bool bits::get(flags flag) { return !!(b & flag); } diff --git a/logic/pipeline.hpp b/logic/pipeline.hpp index 1e1919f4..5c3c3a26 100644 --- a/logic/pipeline.hpp +++ b/logic/pipeline.hpp @@ -35,6 +35,9 @@ namespace gui_tracker_impl { using rmat = euler::rmat; using euler_t = euler::euler_t; +using vec6_bool = Mat<bool, 6, 1>; +using vec3_bool = Mat<bool, 6, 1>; + class reltrans { euler_t interp_pos, last_value; @@ -46,11 +49,13 @@ public: reltrans(); warn_result_unused - euler_t rotate(const rmat& rmat, const euler_t& xyz, - bool disable_tx, bool disable_ty, bool disable_tz) const; + euler_t rotate(const rmat& rmat, const euler_t& in, vec3_bool disable) const; + + warn_result_unused + Pose apply_pipeline(reltrans_state cur, const Pose& value, const vec6_bool& disable); warn_result_unused - Pose apply_pipeline(reltrans_state cur, const Pose& value, const Mat<bool, 6, 1>& disable); + euler_t apply_neck(const Pose& value, bool enable, int nz) const; }; using namespace time_units; @@ -112,6 +117,14 @@ private: double map(double pos, Map& axis); void logic(); void run() override; + void maybe_enable_center_on_tracking_started(); + void maybe_set_center_pose(const Pose& value, bool own_center_logic); + Pose clamp_value(Pose value) const; + Pose apply_center(Pose value) const; + std::tuple<Pose, Pose, vec6_bool> get_selected_axis_value(const Pose& newpose) const; + Pose maybe_apply_filter(const Pose& value) const; + Pose apply_reltrans(Pose value, vec6_bool disabled); + Pose apply_zero_pos(Pose value) const; // note: float exponent base is 2 static constexpr inline double c_mult = 16; @@ -123,11 +136,12 @@ public: void raw_and_mapped_pose(double* mapped, double* raw) const; void start() { QThread::start(QThread::HighPriority); } - void center(); - void set_toggle(bool value); - void set_zero(bool value); - void zero(); + void toggle_zero(); void toggle_enabled(); + + void set_center(); + void set_enabled(bool value); + void set_zero(bool value); }; } // ns impl diff --git a/logic/work.cpp b/logic/work.cpp index cdc27b05..11ec9912 100644 --- a/logic/work.cpp +++ b/logic/work.cpp @@ -65,17 +65,17 @@ Work::Work(Mappings& m, event_handler& ev, QFrame* frame, std::shared_ptr<dylib tracker(std::make_shared<pipeline>(m, libs, ev, *logger)), sc(std::make_shared<Shortcuts>()), keys { - key_tuple(s.key_center1, [&](bool) { tracker->center(); }, true), - key_tuple(s.key_center2, [&](bool) { tracker->center(); }, true), + key_tuple(s.key_center1, [&](bool) { tracker->set_center(); }, true), + key_tuple(s.key_center2, [&](bool) { tracker->set_center(); }, true), key_tuple(s.key_toggle1, [&](bool) { tracker->toggle_enabled(); }, true), key_tuple(s.key_toggle2, [&](bool) { tracker->toggle_enabled(); }, true), - key_tuple(s.key_zero1, [&](bool) { tracker->zero(); }, true), - key_tuple(s.key_zero2, [&](bool) { tracker->zero(); }, true), + key_tuple(s.key_zero1, [&](bool) { tracker->toggle_zero(); }, true), + key_tuple(s.key_zero2, [&](bool) { tracker->toggle_zero(); }, true), - key_tuple(s.key_toggle_press1, [&](bool x) { tracker->set_toggle(!x); }, false), - key_tuple(s.key_toggle_press2, [&](bool x) { tracker->set_toggle(!x); }, false), + key_tuple(s.key_toggle_press1, [&](bool x) { tracker->set_enabled(!x); }, false), + key_tuple(s.key_toggle_press2, [&](bool x) { tracker->set_enabled(!x); }, false), key_tuple(s.key_zero_press1, [&](bool x) { tracker->set_zero(x); }, false), key_tuple(s.key_zero_press2, [&](bool x) { tracker->set_zero(x); }, false), |