53 m_stcWorker->requestCancel();
54 if (m_loadingThread) {
55 m_loadingThread->quit();
56 m_loadingThread->wait();
61 m_stcWorker =
nullptr;
68 const QMap<QString, std::shared_ptr<BrainSurface>>& surfaces,
69 const QString& activeSurfaceType)
72 qWarning() <<
"SourceEstimateManager: STC loading already in progress";
80 const QString lhKey =
"lh_" + activeSurfaceType;
81 const QString rhKey =
"rh_" + activeSurfaceType;
83 if (surfaces.contains(lhKey))
84 lhSurface = surfaces[lhKey].get();
85 if (surfaces.contains(rhKey))
86 rhSurface = surfaces[rhKey].get();
89 if (!lhSurface || !rhSurface) {
90 for (
auto it = surfaces.begin(); it != surfaces.end(); ++it) {
92 if (!lhSurface && it.key().startsWith(
"lh_")) {
93 lhSurface = it.value().get();
94 qDebug() <<
"SourceEstimateManager: Using fallback LH surface:" << it.key();
95 }
else if (!rhSurface && it.key().startsWith(
"rh_")) {
96 rhSurface = it.value().get();
97 qDebug() <<
"SourceEstimateManager: Using fallback RH surface:" << it.key();
103 if (!lhSurface && !rhSurface) {
104 qWarning() <<
"SourceEstimateManager: No surfaces available for STC loading."
105 <<
"Active surface type:" << activeSurfaceType
106 <<
"Available keys:" << surfaces.keys();
112 delete m_loadingThread;
113 m_loadingThread =
nullptr;
116 m_overlay = std::make_unique<SourceEstimateOverlay>();
119 m_loadingThread =
new QThread(
this);
121 m_stcWorker->moveToThread(m_loadingThread);
129 m_loadingThread->start();
138 return m_overlay && m_overlay->isLoaded();
143void SourceEstimateManager::onStcLoadingFinished(
bool success)
147 if (!success || !m_stcWorker) {
148 qWarning() <<
"SourceEstimateManager: Async STC loading failed";
154 if (m_stcWorker->
hasLh()) {
155 m_overlay->setStcData(m_stcWorker->
stcLh(), 0);
160 if (m_stcWorker->hasRh()) {
161 m_overlay->setStcData(m_stcWorker->stcRh(), 1);
162 if (m_stcWorker->interpolationMatRh())
163 m_overlay->setInterpolationMatrix(m_stcWorker->interpolationMatRh(), 1);
166 m_overlay->updateThresholdsFromData();
168 m_overlay->thresholdMid(),
169 m_overlay->thresholdMax());
171 if (m_overlay->isLoaded()) {
172 emit
loaded(m_overlay->numTimePoints());
181 const QMap<QString, std::shared_ptr<BrainSurface>>& surfaces,
183 const QVector<SubView>& subViews)
185 if (!m_overlay || !m_overlay->isLoaded())
188 m_currentTimePoint = qBound(0, index, m_overlay->numTimePoints() - 1);
191 QSet<QString> activeTypes;
193 for (
int i = 0; i < subViews.size(); ++i)
194 activeTypes.insert(subViews[i].surfaceType);
197 for (
auto it = surfaces.begin(); it != surfaces.end(); ++it) {
198 for (
const QString& type : activeTypes) {
199 if (it.key().endsWith(type)) {
200 m_overlay->applyToSurface(it.value().get(), m_currentTimePoint);
206 emit
timePointChanged(m_currentTimePoint, m_overlay->timeAtIndex(m_currentTimePoint));
213 return (m_overlay && m_overlay->isLoaded()) ? m_overlay->tstep() : 0.0f;
220 return (m_overlay && m_overlay->isLoaded()) ? m_overlay->tmin() : 0.0f;
227 return (m_overlay && m_overlay->isLoaded()) ? m_overlay->numTimePoints() : 0;
234 if (!m_overlay || !m_overlay->isLoaded())
237 const float t0 = m_overlay->tmin();
238 const float dt = m_overlay->tstep();
239 const int numPts = m_overlay->numTimePoints();
240 if (numPts <= 0 || dt <= 0.0f)
243 const int idx = qRound((timeSec - t0) / dt);
244 return qBound(0, idx, numPts - 1);
252 m_overlay->setColormap(name);
260 m_overlay->setThresholds(min, mid, max);
263 m_rtController->setThresholds(min, mid, max);
270 const QVector<SubView>& subViews)
277 qDebug() <<
"SourceEstimateManager: Real-time streaming already active";
281 if (!m_overlay || !m_overlay->isLoaded()) {
282 qWarning() <<
"SourceEstimateManager: Cannot start streaming — no source estimate loaded";
287 if (!m_rtController) {
288 m_rtController = std::make_unique<RtSourceDataController>(
this);
294 m_rtController->setInterpolationMatrixLeft(m_overlay->interpolationMatLh());
295 m_rtController->setInterpolationMatrixRight(m_overlay->interpolationMatRh());
298 m_rtController->setColormapType(m_overlay->colormap());
299 m_rtController->setThresholds(m_overlay->thresholdMin(),
300 m_overlay->thresholdMid(),
301 m_overlay->thresholdMax());
302 m_rtController->setSFreq(1.0 / m_overlay->tstep());
305 const int nTimePoints = m_overlay->numTimePoints();
306 qDebug() <<
"SourceEstimateManager: Feeding" << nTimePoints <<
"time points into real-time queue";
307 m_rtController->clearData();
309 for (
int t = 0; t < nTimePoints; ++t) {
310 Eigen::VectorXd col = m_overlay->sourceDataColumn(t);
312 m_rtController->addData(col);
315 m_rtController->setStreamingState(
true);
316 m_isStreaming =
true;
318 qDebug() <<
"SourceEstimateManager: Real-time streaming started";
329 m_rtController->setStreamingState(
false);
331 m_isStreaming =
false;
332 qDebug() <<
"SourceEstimateManager: Real-time streaming stopped";
340 m_rtController->addData(data);
348 m_rtController->setTimeInterval(msec);
356 m_rtController->setLoopState(enabled);
363 return m_overlay.get();
Background worker that loads source-time-course (.stc) files and prepares per-hemisphere interpolatio...
Real-time source-estimate streaming controller that owns the data worker and the per-hemisphere inter...
Renderable cortical / BEM mesh with interleaved vertex attributes and Qt-RHI buffer management.
Colour-mapped source-time-course overlay that interpolates STC activation onto a cortical mesh and up...
Per-viewport state (camera preset, zoom, pan, visibility filter) and serialisation helpers.
Owns the source-time-course overlay together with its loader, real-time controller and target cortica...
3-D brain visualisation using the Qt RHI rendering backend.
Viewport subdivision holding its own camera, projection, and scissor rectangle.
Renderable cortical surface mesh with per-vertex color, curvature data, and GPU buffer management.
Color-mapped source estimate overlay that interpolates activation values onto a cortical surface mesh...
int numTimePoints() const
bool load(const QString &lhPath, const QString &rhPath, const QMap< QString, std::shared_ptr< BrainSurface > > &surfaces, const QString &activeSurfaceType)
const SourceEstimateOverlay * overlay() const
void setThresholds(float min, float mid, float max)
void loadingProgress(int percent, const QString &message)
SourceEstimateManager(QObject *parent=nullptr)
int closestIndex(float timeSec) const
void loaded(int numTimePoints)
void realtimeColorsAvailable(const QVector< uint32_t > &colorsLh, const QVector< uint32_t > &colorsRh)
void timePointChanged(int index, float time)
void setColormap(const QString &name)
void thresholdsUpdated(float min, float mid, float max)
void setInterval(int msec)
void startStreaming(const QMap< QString, std::shared_ptr< BrainSurface > > &surfaces, const SubView &singleView, const QVector< SubView > &subViews)
void setLooping(bool enabled)
void setTimePoint(int index, const QMap< QString, std::shared_ptr< BrainSurface > > &surfaces, const SubView &singleView, const QVector< SubView > &subViews)
~SourceEstimateManager() override
void pushData(const Eigen::VectorXd &data)
void newSmoothedDataAvailable(const QVector< uint32_t > &colorsLh, const QVector< uint32_t > &colorsRh)
Background worker that loads source estimate (STC) files and emits loaded data for visualization.
void finished(bool success)
void progress(int percent, const QString &message)
QSharedPointer< Eigen::SparseMatrix< float > > interpolationMatLh() const
const INVLIB::InvSourceEstimate & stcLh() const