74 qWarning() <<
"SourceEstimateOverlay::loadStc - Failed to read STC file:" << path;
81 qDebug() <<
"SourceEstimateOverlay: Loaded LH with" << stc.
data.rows() <<
"vertices,"
82 << stc.
data.cols() <<
"time points";
86 qDebug() <<
"SourceEstimateOverlay: Loaded RH with" << stc.
data.rows() <<
"vertices,"
87 << stc.
data.cols() <<
"time points";
91 if (m_hasLh || m_hasRh) {
92 double minVal, maxVal;
96 m_threshMid = (minVal + maxVal) / 2.0;
97 qDebug() <<
"SourceEstimateOverlay: Auto thresholds set to" << m_threshMin << m_threshMid << m_threshMax;
107 return m_hasLh || m_hasRh;
114 if (!surface)
return;
116 int hemi = surface->
hemi();
118 QSharedPointer<Eigen::SparseMatrix<float>> interpMat;
120 if (hemi == 0 && m_hasLh) {
122 interpMat = m_interpolationMatLh;
123 }
else if (hemi == 1 && m_hasRh) {
125 interpMat = m_interpolationMatRh;
133 int tIdx = qBound(0, timeIndex,
static_cast<int>(stc->
data.cols()) - 1);
136 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);
211 if (m_hasLh)
return m_stcLh.data.cols();
212 if (m_hasRh)
return m_stcRh.data.cols();
220 if (m_hasLh && idx < m_stcLh.times.size()) {
221 return m_stcLh.times(idx);
223 if (m_hasRh && idx < m_stcRh.times.size()) {
224 return m_stcRh.times(idx);
233 if (m_hasLh)
return m_stcLh.tmin;
234 if (m_hasRh)
return m_stcRh.tmin;
242 if (m_hasLh)
return m_stcLh.tstep;
243 if (m_hasRh)
return m_stcRh.tstep;
251 minVal = std::numeric_limits<double>::max();
252 maxVal = std::numeric_limits<double>::lowest();
255 double lhMin = m_stcLh.data.minCoeff();
256 double lhMax = m_stcLh.data.maxCoeff();
257 minVal = qMin(minVal, std::abs(lhMin));
258 maxVal = qMax(maxVal, std::abs(lhMax));
262 double rhMin = m_stcRh.data.minCoeff();
263 double rhMax = m_stcRh.data.maxCoeff();
264 minVal = qMin(minVal, std::abs(rhMin));
265 maxVal = qMax(maxVal, std::abs(rhMax));
269 if (minVal > maxVal) {
277uint32_t SourceEstimateOverlay::valueToColor(
double value, uint8_t alpha)
const
281 uint32_t r = qRed(rgb);
282 uint32_t g = qGreen(rgb);
283 uint32_t b = qBlue(rgb);
286 return packABGR(r, g, b,
static_cast<uint32_t
>(alpha));
293 if (!surface)
return;
296 QSharedPointer<Eigen::SparseMatrix<float>> *pMatPtr =
nullptr;
298 if (hemi == 0 && m_hasLh) {
300 pMatPtr = &m_interpolationMatLh;
301 }
else if (hemi == 1 && m_hasRh) {
303 pMatPtr = &m_interpolationMatRh;
310 qDebug() <<
"SourceEstimateOverlay: Computing interpolation matrix for hemi" << hemi;
317 Eigen::VectorXi vecSourceVertices = stc->
vertices;
319 qDebug() <<
"SourceEstimateOverlay: Surface has" << matVertices.rows() <<
"vertices,"
320 << vecSourceVertices.size() <<
"sources";
322 if (vecSourceVertices.size() == 0) {
323 qWarning() <<
"SourceEstimateOverlay: No source vertices found";
330 qDebug() <<
"SourceEstimateOverlay: Computing distance table (SCDC)...";
338 if (!distTable || distTable->rows() == 0) {
339 qWarning() <<
"SourceEstimateOverlay: Failed to compute distance table";
344 qDebug() <<
"SourceEstimateOverlay: Creating interpolation matrix...";
352 if (*pMatPtr && (*pMatPtr)->rows() > 0) {
353 qDebug() <<
"SourceEstimateOverlay: Interpolation matrix created:"
354 << (*pMatPtr)->rows() <<
"x" << (*pMatPtr)->cols();
356 qWarning() <<
"SourceEstimateOverlay: Failed to compute interpolation matrix";
378 m_interpolationMatLh = mat;
380 m_interpolationMatRh = mat;
388 if (m_hasLh || m_hasRh) {
389 double minVal, maxVal;
391 m_threshMin = minVal;
392 m_threshMax = maxVal;
393 m_threshMid = (minVal + maxVal) / 2.0;
394 qDebug() <<
"SourceEstimateOverlay: Auto thresholds set to" << m_threshMin << m_threshMid << m_threshMax;
402 int nLh = m_hasLh ? m_stcLh.data.rows() : 0;
403 int nRh = m_hasRh ? m_stcRh.data.rows() : 0;
405 if (nLh == 0 && nRh == 0) {
406 return Eigen::VectorXd();
409 Eigen::VectorXd result(nLh + nRh);
412 int tIdx = qBound(0, timeIndex,
static_cast<int>(m_stcLh.data.cols()) - 1);
413 result.head(nLh) = m_stcLh.data.col(tIdx);
417 int tIdx = qBound(0, timeIndex,
static_cast<int>(m_stcRh.data.cols()) - 1);
418 result.segment(nLh, nRh) = m_stcRh.data.col(tIdx);
ColorMap class declaration.
BrainSurface class declaration.
SourceEstimateOverlay class declaration.
GeometryInfo class declaration.
Interpolation class declaration.
Lightweight render-related enums shared across the disp3D_rhi library.
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.
uint32_t vertexCount() const
void applySourceEstimateColors(const QVector< uint32_t > &colors)
Eigen::MatrixX3f verticesAsMatrix() const
std::vector< Eigen::VectorXi > computeNeighbors() const
Eigen::VectorXd sourceDataColumn(int timeIndex) const
void getDataRange(double &minVal, double &maxVal) const
void setThresholds(float min, float mid, float max)
void applyToSurface(BrainSurface *surface, int timeIndex)
void setStcData(const MNELIB::MNESourceEstimate &stc, int hemi)
float timeAtIndex(int idx) const
int numTimePoints() const
void computeInterpolationMatrix(BrainSurface *surface, int hemi, double cancelDist=0.05)
void setColormap(const QString &name)
void updateThresholdsFromData()
void setInterpolationMatrix(QSharedPointer< Eigen::SparseMatrix< float > > mat, int hemi)
bool loadStc(const QString &path, int hemi)
static bool read(QIODevice &p_IODevice, MNESourceEstimate &p_stc)