v2.0.0
Loading...
Searching...
No Matches
fastrak_parser.cpp
Go to the documentation of this file.
1//=============================================================================================================
22
23#include "fastrak_parser.h"
24
25using namespace UTILSLIB;
26
27namespace {
28
29constexpr float kInchToMetre = 0.0254f;
30constexpr float kCentimetreToMetre = 0.01f;
31
32float linearScale(FastrakParser::Units units)
33{
34 return (units == FastrakParser::Units::Inches) ? kInchToMetre
35 : kCentimetreToMetre;
36}
37
38} // namespace
39
40//=============================================================================================================
41
42bool FastrakParser::parseRecord(const QByteArray& record, Units units, FastrakSample& out)
43{
44 // Fastrak uses fixed-width ASCII fields. When a negative value
45 // immediately follows a positive one the minus sign eats the
46 // separating space, e.g. "0.8829-0.3055". Insert a space before
47 // every '-' that is preceded by a digit so tokenisation works.
48 QByteArray fixed = record.simplified();
49 for (int i = fixed.size() - 1; i > 0; --i) {
50 const char c = fixed.at(i);
51 const char pc = fixed.at(i - 1);
52 if (c == '-' && pc >= '0' && pc <= '9') {
53 fixed.insert(i, ' ');
54 }
55 }
56
57 const QList<QByteArray> tokens = fixed.split(' ');
58 if (tokens.size() < 4) {
59 return false;
60 }
61
62 bool ok = false;
63 const int station = tokens[0].toInt(&ok);
64 if (!ok) {
65 return false;
66 }
67
68 auto parseFloat = [&ok](const QByteArray& t) -> float {
69 bool good = false;
70 const float v = t.toFloat(&good);
71 ok = ok && good;
72 return v;
73 };
74
75 ok = true;
76 const float x = parseFloat(tokens[1]);
77 const float y = parseFloat(tokens[2]);
78 const float z = parseFloat(tokens[3]);
79 if (!ok) {
80 return false;
81 }
82
83 const float scale = linearScale(units);
84 out.station = station;
85 out.position = QVector3D(x * scale, y * scale, z * scale);
86 out.hasOrientation = false;
87 out.orientation = QQuaternion();
88
89 if (tokens.size() >= 8) {
90 // Quaternion output (O-item 11): q0 q1 q2 q3 (scalar-first).
91 // No gimbal lock — preferred over Euler angles.
92 const float q0 = parseFloat(tokens[4]);
93 const float q1 = parseFloat(tokens[5]);
94 const float q2 = parseFloat(tokens[6]);
95 const float q3 = parseFloat(tokens[7]);
96 if (ok) {
97 out.orientation = QQuaternion(q0, q1, q2, q3).normalized();
98 out.hasOrientation = true;
99 }
100 } else if (tokens.size() >= 7) {
101 // Euler angle output (O-item 4): azimuth, elevation, roll.
102 // Kept for backward compatibility; suffers from gimbal lock at elevation ±90°.
103 const float az = parseFloat(tokens[4]);
104 const float el = parseFloat(tokens[5]);
105 const float ro = parseFloat(tokens[6]);
106 if (ok) {
107 const QQuaternion qZ = QQuaternion::fromAxisAndAngle(0.0f, 0.0f, 1.0f, az);
108 const QQuaternion qY = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, el);
109 const QQuaternion qX = QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, ro);
110 out.orientation = qZ * qY * qX;
111 out.hasOrientation = true;
112 }
113 }
114
115 return true;
116}
117
118//=============================================================================================================
119
121{
122 while (true) {
123 const int eol = m_buffer.indexOf('\n');
124 if (eol < 0) {
125 return false;
126 }
127
128 QByteArray line = m_buffer.left(eol);
129 m_buffer.remove(0, eol + 1);
130 if (line.endsWith('\r')) {
131 line.chop(1);
132 }
133 if (line.trimmed().isEmpty()) {
134 continue; // skip blank line, keep scanning
135 }
136 if (parseRecord(line, m_units, out)) {
137 return true;
138 }
139 // malformed line → drop and keep scanning
140 }
141}
Polhemus Fastrak / FastSCAN ASCII record parser.
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
One decoded sample from a Fastrak ASCII stream.
QVector3D position
Position in metres (always normalised to SI).
QQuaternion orientation
Sensor orientation; identity if not provided.
int station
1-based station id reported by the device.
bool nextSample(FastrakSample &out)
@ Inches
Fastrak factory default.
static bool parseRecord(const QByteArray &record, Units units, FastrakSample &out)