v2.0.0
Loading...
Searching...
No Matches
rtsensordataworker.cpp
Go to the documentation of this file.
1//=============================================================================================================
12
13//=============================================================================================================
14// INCLUDES
15//=============================================================================================================
16
17#include "rtsensordataworker.h"
18#include "core/rendertypes.h"
19
21#include <QMutexLocker>
22#include <QDebug>
23#include <cmath>
24
25using namespace DISP3DLIB;
26
27//=============================================================================================================
28// DEFINE MEMBER METHODS
29//=============================================================================================================
30
32 : QObject(parent)
33{
34}
35
36//=============================================================================================================
37
38void RtSensorDataWorker::addData(const Eigen::VectorXf &data)
39{
40 QMutexLocker locker(&m_mutex);
41
42 // Cap queue size at sampling frequency (1 second of data)
43 if (m_lDataQ.size() < static_cast<int>(m_dSFreq)) {
44 m_lDataQ.append(data);
45 }
46
47 // Also store for looping
48 if (m_bIsLooping) {
49 m_lDataLoopQ.append(data);
50 // Cap loop queue at 10 seconds of data
51 if (m_lDataLoopQ.size() > static_cast<int>(m_dSFreq) * 10) {
52 m_lDataLoopQ.removeFirst();
53 }
54 }
55}
56
57//=============================================================================================================
58
60{
61 QMutexLocker locker(&m_mutex);
62 m_lDataQ.clear();
63 m_lDataLoopQ.clear();
64 m_vecAverage = Eigen::VectorXf();
65 m_iSampleCtr = 0;
66 m_iCurrentSample = 0;
67}
68
69//=============================================================================================================
70
71void RtSensorDataWorker::setMappingMatrix(std::shared_ptr<Eigen::MatrixXf> mat)
72{
73 QMutexLocker locker(&m_mutex);
74 m_mappingMat = mat;
75}
76
77//=============================================================================================================
78
80{
81 QMutexLocker locker(&m_mutex);
82 m_iNumAverages = qMax(1, numAvr);
83}
84
85//=============================================================================================================
86
87void RtSensorDataWorker::setColormapType(const QString &name)
88{
89 QMutexLocker locker(&m_mutex);
90 m_sColormapType = name;
91}
92
93//=============================================================================================================
94
95void RtSensorDataWorker::setThresholds(double min, double max)
96{
97 QMutexLocker locker(&m_mutex);
98 if (min == 0.0 && max == 0.0) {
99 m_bUseAutoNorm = true;
100 m_dThreshMin = 0.0;
101 m_dThreshMax = 0.0;
102 } else {
103 m_bUseAutoNorm = false;
104 m_dThreshMin = min;
105 m_dThreshMax = max;
106 }
107}
108
109//=============================================================================================================
110
112{
113 QMutexLocker locker(&m_mutex);
114 m_bIsLooping = enabled;
115}
116
117//=============================================================================================================
118
120{
121 QMutexLocker locker(&m_mutex);
122 m_dSFreq = qMax(1.0, sFreq);
123}
124
125//=============================================================================================================
126
127void RtSensorDataWorker::setStreamSmoothedData(bool bStreamSmoothedData)
128{
129 QMutexLocker locker(&m_mutex);
130 m_bStreamSmoothedData = bStreamSmoothedData;
131}
132
133//=============================================================================================================
134
136{
137 QMutexLocker locker(&m_mutex);
138
139 // Try to get data from queue
140 Eigen::VectorXf vecCurrentData;
141
142 if (!m_lDataQ.isEmpty()) {
143 vecCurrentData = m_lDataQ.takeFirst();
144 } else if (m_bIsLooping && !m_lDataLoopQ.isEmpty()) {
145 // Loop: replay from stored data
146 vecCurrentData = m_lDataLoopQ[m_iCurrentSample % m_lDataLoopQ.size()];
147 m_iCurrentSample++;
148 } else {
149 // No data available
150 return;
151 }
152
153 // Averaging
154 if (m_iNumAverages > 1) {
155 if (m_vecAverage.size() != vecCurrentData.size()) {
156 m_vecAverage = vecCurrentData;
157 m_iSampleCtr = 1;
158 } else {
159 m_vecAverage += vecCurrentData;
160 m_iSampleCtr++;
161 }
162
163 if (m_iSampleCtr < m_iNumAverages) {
164 return; // Accumulate more samples
165 }
166
167 vecCurrentData = m_vecAverage / static_cast<float>(m_iSampleCtr);
168 m_vecAverage = Eigen::VectorXf();
169 m_iSampleCtr = 0;
170 }
171
172 // Check streaming mode
173 if (!m_bStreamSmoothedData) {
174 // Raw mode: emit measurement vector without mapping
175 Eigen::VectorXf rawData = vecCurrentData;
176 locker.unlock();
177 emit newRtRawSensorData(rawData);
178 return;
179 }
180
181 // Compute per-vertex colors using the dense mapping matrix
182 QVector<uint32_t> colors = computeSurfaceColors(vecCurrentData);
183
184 // Unlock before emitting (avoid deadlock if slot is direct connection)
185 locker.unlock();
186
187 if (!colors.isEmpty()) {
188 emit newRtSensorColors(m_sSurfaceKey, colors);
189 }
190}
191
192//=============================================================================================================
193
194QVector<uint32_t> RtSensorDataWorker::computeSurfaceColors(const Eigen::VectorXf &sensorData) const
195{
196 if (sensorData.size() == 0 || !m_mappingMat || m_mappingMat->rows() == 0) {
197 return QVector<uint32_t>();
198 }
199
200 // Validate dimensions
201 if (m_mappingMat->cols() != sensorData.size()) {
202 qWarning() << "RtSensorDataWorker: Mapping matrix cols" << m_mappingMat->cols()
203 << "!= sensor data size" << sensorData.size();
204 return QVector<uint32_t>();
205 }
206
207 // Map sensor data to surface vertices: mapped = M * meas
208 Eigen::VectorXf mapped = (*m_mappingMat) * sensorData;
209
210 int nVertices = mapped.size();
211
212 // Determine normalization range
213 float normMin, normMax;
214 if (m_bUseAutoNorm) {
215 // Symmetric auto-normalization: ±maxAbs
216 float maxAbs = 0.0f;
217 for (int i = 0; i < nVertices; ++i) {
218 maxAbs = std::max(maxAbs, std::abs(mapped(i)));
219 }
220 if (maxAbs <= 0.0f) maxAbs = 1.0f;
221 normMin = -maxAbs;
222 normMax = maxAbs;
223 } else {
224 // Explicit thresholds
225 normMin = static_cast<float>(m_dThreshMin);
226 normMax = static_cast<float>(m_dThreshMax);
227 if (normMax <= normMin) normMax = normMin + 1.0f;
228 }
229
230 float range = normMax - normMin;
231
232 // Convert to per-vertex ABGR colours
233 QVector<uint32_t> colors(nVertices);
234
235 for (int i = 0; i < nVertices; ++i) {
236 // Normalisation: map [normMin, normMax] → [0, 1]
237 double norm = static_cast<double>(mapped(i) - normMin) / static_cast<double>(range);
238 norm = qBound(0.0, norm, 1.0);
239
240 QRgb rgb = DISPLIB::ColorMap::valueToColor(norm, m_sColormapType);
241
242 uint32_t r = qRed(rgb);
243 uint32_t g = qGreen(rgb);
244 uint32_t b = qBlue(rgb);
245
246 // Pack as ABGR (same format as BrainSurface uses)
247 colors[i] = packABGR(r, g, b);
248 }
249
250 return colors;
251}
Background worker that turns queued sensor packets into per-vertex ABGR colour buffers via a dense ma...
Lightweight render-related enums (ShaderMode, VisualizationMode) shared across disp3D.
uint32_t packABGR(uint32_t r, uint32_t g, uint32_t b, uint32_t a=0xFF)
Definition rendertypes.h:48
Static scalar-to-colour lookup helpers (Jet, Hot, Bone, Viridis, Cool, RedBlue, MNE) used by every pl...
3-D brain visualisation using the Qt RHI rendering backend.
static QRgb valueToColor(double v, const QString &sMap)
Definition colormap.h:681
void newRtSensorColors(const QString &surfaceKey, const QVector< uint32_t > &colors)
void setThresholds(double min, double max)
void addData(const Eigen::VectorXf &data)
RtSensorDataWorker(QObject *parent=nullptr)
void setMappingMatrix(std::shared_ptr< Eigen::MatrixXf > mat)
void setColormapType(const QString &name)
void setStreamSmoothedData(bool bStreamSmoothedData)
void newRtRawSensorData(const Eigen::VectorXf &data)