summaryrefslogtreecommitdiffhomepage
path: root/logic
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2018-02-05 09:33:00 +0100
committerStanislaw Halik <sthalik@misaki.pl>2018-02-16 19:15:47 +0100
commit664f9c94fbb570f0b5abae1b36c5940275813096 (patch)
treeab4b62edf3521ee0a6fe2cbad716dcb5d867c1cf /logic
parentb52fd95f1cc86e86ecb696eab07c8d6b6a2e9f5d (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
Diffstat (limited to 'logic')
-rw-r--r--logic/pipeline.cpp435
-rw-r--r--logic/pipeline.hpp28
-rw-r--r--logic/work.cpp12
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),