55 qWarning() <<
"SourceEstimateOverlay::loadStc - Failed to read STC file:" << path;
62 qDebug() <<
"SourceEstimateOverlay: Loaded LH with" << stc.
data.rows() <<
"vertices,"
63 << stc.
data.cols() <<
"time points";
67 qDebug() <<
"SourceEstimateOverlay: Loaded RH with" << stc.
data.rows() <<
"vertices,"
68 << stc.
data.cols() <<
"time points";
70 invalidateColorCache();
73 if (m_hasLh || m_hasRh) {
74 double minVal, maxVal;
78 m_threshMid = (minVal + maxVal) / 2.0;
79 qDebug() <<
"SourceEstimateOverlay: Auto thresholds set to" << m_threshMin << m_threshMid << m_threshMax;
89 return m_hasLh || m_hasRh;
99 int hemi = surface->
hemi();
101 QSharedPointer<Eigen::SparseMatrix<float>> interpMat;
103 if (hemi == 0 && m_hasLh) {
105 interpMat = m_interpolationMatLh;
106 }
else if (hemi == 1 && m_hasRh) {
108 interpMat = m_interpolationMatRh;
117 int tIdx = qBound(0, timeIndex,
static_cast<int>(stc->
data.cols()) - 1);
118 const uint32_t vertexCount = surface->
vertexCount();
126 const ColorCacheKey cacheKey(hemi,
static_cast<int>(vertexCount));
127 auto bucketIt = m_colorCache.find(cacheKey);
128 if (bucketIt != m_colorCache.end()) {
129 auto frameIt = bucketIt.value().constFind(tIdx);
130 if (frameIt != bucketIt.value().constEnd()) {
137 Eigen::VectorXf sourceData = stc->
data.col(tIdx).cwiseAbs().cast<
float>();
140 QVector<uint32_t> colors(vertexCount, 0xFF808080);
143 Eigen::VectorXf interpolatedData;
145 if (interpMat && interpMat->rows() ==
static_cast<int>(vertexCount) &&
146 interpMat->cols() == sourceData.size()) {
152 interpolatedData = Eigen::VectorXf::Zero(vertexCount);
153 const Eigen::VectorXi& srcVertices = stc->
vertices;
154 for (
int i = 0; i < srcVertices.size() && i < sourceData.size(); ++i) {
155 int vertIdx = srcVertices(i);
156 if (vertIdx >= 0 && vertIdx <
static_cast<int>(vertexCount)) {
157 interpolatedData(vertIdx) = sourceData(i);
163 for (
int i = 0; i < static_cast<int>(vertexCount); ++i) {
164 float value = interpolatedData(i);
167 double normalized = 0.0;
168 if (m_threshMax > m_threshMin) {
169 normalized = (value - m_threshMin) / (m_threshMax - m_threshMin);
170 normalized = qBound(0.0, normalized, 1.0);
175 if (value < m_threshMin) {
177 }
else if (value < m_threshMid) {
179 float range = m_threshMid - m_threshMin;
181 alpha =
static_cast<uint8_t
>(255.0f * (value - m_threshMin) / range);
185 colors[i] = valueToColor(normalized, alpha);
190 m_colorCache[cacheKey].insert(tIdx, colors);
199 if (m_colormap == name)
202 invalidateColorCache();
209 if (m_threshMin == min && m_threshMid == mid && m_threshMax == max)
214 invalidateColorCache();
222 return m_stcLh.data.cols();
224 return m_stcRh.data.cols();
232 if (m_hasLh && idx < m_stcLh.times.size()) {
233 return m_stcLh.times(idx);
235 if (m_hasRh && idx < m_stcRh.times.size()) {
236 return m_stcRh.times(idx);
257 return m_stcLh.tstep;
259 return m_stcRh.tstep;
267 minVal = std::numeric_limits<double>::max();
268 maxVal = std::numeric_limits<double>::lowest();
272 if (stc && stc->data.size() > 0) {
273 minVal = qMin(minVal, stc->data.cwiseAbs().minCoeff());
274 maxVal = qMax(maxVal, stc->data.cwiseAbs().maxCoeff());
279 if (minVal > maxVal) {
287uint32_t SourceEstimateOverlay::valueToColor(
double value, uint8_t alpha)
const
291 uint32_t r = qRed(rgb);
292 uint32_t g = qGreen(rgb);
293 uint32_t b = qBlue(rgb);
296 return packABGR(r, g, b,
static_cast<uint32_t
>(alpha));
307 QSharedPointer<Eigen::SparseMatrix<float>>* pMatPtr =
nullptr;
309 if (hemi == 0 && m_hasLh) {
311 pMatPtr = &m_interpolationMatLh;
312 }
else if (hemi == 1 && m_hasRh) {
314 pMatPtr = &m_interpolationMatRh;
322 qDebug() <<
"SourceEstimateOverlay: Computing interpolation matrix for hemi" << hemi;
329 Eigen::VectorXi vecSourceVertices = stc->
vertices;
331 qDebug() <<
"SourceEstimateOverlay: FsSurface has" << matVertices.rows() <<
"vertices,"
332 << vecSourceVertices.size() <<
"sources";
334 if (vecSourceVertices.size() == 0) {
335 qWarning() <<
"SourceEstimateOverlay: No source vertices found";
342 qDebug() <<
"SourceEstimateOverlay: Computing distance table (SCDC)...";
349 if (!distTable || distTable->rows() == 0) {
350 qWarning() <<
"SourceEstimateOverlay: Failed to compute distance table";
355 qDebug() <<
"SourceEstimateOverlay: Creating interpolation matrix...";
362 if (*pMatPtr && (*pMatPtr)->rows() > 0) {
363 qDebug() <<
"SourceEstimateOverlay: Interpolation matrix created:"
364 << (*pMatPtr)->rows() <<
"x" << (*pMatPtr)->cols();
366 qWarning() <<
"SourceEstimateOverlay: Failed to compute interpolation matrix";
381 invalidateColorCache();
389 m_interpolationMatLh = mat;
391 m_interpolationMatRh = mat;
393 invalidateColorCache();
400 if (m_hasLh || m_hasRh) {
401 double minVal, maxVal;
403 m_threshMin = minVal;
404 m_threshMax = maxVal;
405 m_threshMid = (minVal + maxVal) / 2.0;
406 invalidateColorCache();
407 qDebug() <<
"SourceEstimateOverlay: Auto thresholds set to" << m_threshMin << m_threshMid << m_threshMax;
415 int nLh = m_hasLh ? m_stcLh.data.rows() : 0;
416 int nRh = m_hasRh ? m_stcRh.data.rows() : 0;
418 if (nLh == 0 && nRh == 0) {
419 return Eigen::VectorXd();
422 Eigen::VectorXd result(nLh + nRh);
425 int tIdx = qBound(0, timeIndex,
static_cast<int>(m_stcLh.data.cols()) - 1);
426 result.head(nLh) = m_stcLh.data.col(tIdx);
430 int tIdx = qBound(0, timeIndex,
static_cast<int>(m_stcRh.data.cols()) - 1);
431 result.segment(nLh, nRh) = m_stcRh.data.col(tIdx);
Static scalar-to-colour lookup helpers (Jet, Hot, Bone, Viridis, Cool, RedBlue, MNE) used by every pl...
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...
Distance-based sparse interpolation weights and per-frame signal smoothing on triangulated meshes.
Surface-constrained geodesic distance and sensor-to-mesh projection helpers.
Lightweight render-related enums (ShaderMode, VisualizationMode) shared across disp3D.
3-D brain visualisation using the Qt RHI rendering backend.
uint32_t packABGR(uint32_t r, uint32_t g, uint32_t b, uint32_t a=0xFF)
static QRgb valueToColor(double v, const QString &sMap)
static QSharedPointer< Eigen::MatrixXd > scdc(const Eigen::MatrixX3f &matVertices, const std::vector< Eigen::VectorXi > &vecNeighborVertices, Eigen::VectorXi &vecVertSubset, double dCancelDist=FLOAT_INFINITY)
scdc Calculates surface constrained distances on a mesh.
static Eigen::VectorXf interpolateSignal(const QSharedPointer< Eigen::SparseMatrix< float > > matInterpolationMatrix, const QSharedPointer< Eigen::VectorXf > &vecMeasurementData)
interpolateSignal Interpolates sensor data using the weight matrix (shared pointer version).
static double cubic(const double dIn)
cubic Cubic hyperbola interpolation function.
static QSharedPointer< Eigen::SparseMatrix< float > > createInterpolationMat(const Eigen::VectorXi &vecProjectedSensors, const QSharedPointer< Eigen::MatrixXd > matDistanceTable, double(*interpolationFunction)(double), const double dCancelDist=FLOAT_INFINITY, const Eigen::VectorXi &vecExcludeIndex=Eigen::VectorXi())
createInterpolationMat Calculates the weight matrix for interpolation.
Renderable cortical surface mesh with per-vertex color, curvature data, and GPU buffer management.
Eigen::MatrixX3f verticesAsMatrix() const
uint32_t vertexCount() const
void applySourceEstimateColors(const QVector< uint32_t > &colors)
std::vector< Eigen::VectorXi > computeNeighbors() const
void setThresholds(float min, float mid, float max)
int numTimePoints() const
void applyToSurface(BrainSurface *surface, int timeIndex)
Eigen::VectorXd sourceDataColumn(int timeIndex) const
bool loadStc(const QString &path, int hemi)
void updateThresholdsFromData()
float timeAtIndex(int idx) const
void getDataRange(double &minVal, double &maxVal) const
void computeInterpolationMatrix(BrainSurface *surface, int hemi, double cancelDist=0.05)
void setColormap(const QString &name)
void setInterpolationMatrix(QSharedPointer< Eigen::SparseMatrix< float > > mat, int hemi)
void setStcData(const INVLIB::InvSourceEstimate &stc, int hemi)
Source-space inverse-solution container with dense grid plus optional focal-dipole,...
static bool read(QIODevice &p_IODevice, InvSourceEstimate &p_stc)