37#ifndef _USE_MATH_DEFINES
38#define _USE_MATH_DEFINES
64, trans(MatrixXf::Identity(4, 4))
65, invtrans(MatrixXf::Identity(4, 4))
74, trans(MatrixXf::Identity(4, 4))
75, invtrans(MatrixXf::Identity(4, 4))
77 if (!read(p_IODevice, *
this)) {
78 throw std::runtime_error(
"Coordinate transform not found");
85: from(p_FiffCoordTrans.from)
86, to(p_FiffCoordTrans.to)
87, trans(p_FiffCoordTrans.trans)
88, invtrans(p_FiffCoordTrans.invtrans)
114 this->
from = from_new;
125 FiffStream::SPtr pStream(
new FiffStream(&p_IODevice));
127 qInfo(
"Reading coordinate transform from %s...\n", pStream->streamName().toUtf8().constData());
128 if (!pStream->open())
134 FiffTag::UPtr t_pTag;
135 bool success =
false;
140 for (qint32 k = 0; k < pStream->dir().size() && !success; ++k) {
141 if (pStream->dir()[k]->kind ==
FIFF_COORD_TRANS && pStream->read_tag(t_pTag, pStream->dir()[k]->pos)) {
142 p_Trans = t_pTag->toCoordTrans();
155 FiffStream::SPtr pStream = FiffStream::start_file(qIODevice);
159 qInfo(
"Write coordinate transform in %s...\n", pStream->streamName().toUtf8().constData());
177 MatrixX4f rr_ones(rr.rows(), 4);
183 rr_ones.block(0, 0, rr.rows(), 3) = rr;
184 return rr_ones *
trans.block<3, 4>(0, 0).transpose();
191 MatrixX4f rr_ones(rr.rows(), 4);
197 rr_ones.block(0, 0, rr.rows(), 3) = rr;
198 return rr_ones *
invtrans.block<3, 4>(0, 0).transpose();
217 return "MRI (surface RAS)";
223 return "MRI display";
225 return "CTF MEG device";
227 return "CTF/4D/KIT head";
229 return "RAS (non-zero origin)";
231 return "MNI Talairach";
233 return "Talairach (MNI z > 0)";
235 return "Talairach (MNI z < 0)";
245 this->
trans = MatrixXf::Zero(4, 4);
250 this->
trans.block<3, 3>(0, 0) =
rot;
252 this->
trans(3, 3) = 1.0f;
261 this->
trans = matTrans;
267 this->
trans.row(3) = Vector4f(0, 0, 0, 1).transpose();
287 for (
int p = 0; p < 3; p++)
288 qInfo(
"\t% 8.6f % 8.6f % 8.6f\t% 7.2f mm",
trans(p, 0),
trans(p, 1),
trans(p, 2), 1000 *
trans(p, 3));
296 MatrixX4f mDevHeadT = this->
trans;
297 Matrix3f mRot = mDevHeadT.block(0, 0, 3, 3);
298 Matrix3f mRotNew = mTransDest.block(0, 0, 3, 3);
300 Quaternionf quat(mRot);
301 Quaternionf quatNew(mRotNew);
306 Quaternionf quatCompare;
308 quatCompare = quat * quatNew.inverse();
309 fAngle = quat.angularDistance(quatNew);
310 fAngle = fAngle * 180 / M_PI;
319 VectorXf vTrans = this->
trans.col(3);
320 VectorXf vTransDest = mTransDest.col(3);
322 float fMove = (vTrans - vTransDest).norm();
331 for (
int j = 0; j < 3; j++) {
332 res[j] = do_move ? t.
trans(j, 3) : 0.0f;
333 for (
int k = 0; k < 3; k++)
334 res[j] += t.
trans(j, k) * r[k];
336 for (
int j = 0; j < 3; j++)
345 for (
int j = 0; j < 3; j++) {
346 res[j] = do_move ? t.
invtrans(j, 3) : 0.0f;
347 for (
int k = 0; k < 3; k++)
350 for (
int j = 0; j < 3; j++)
384 for (
int swapped = 0; swapped < 2 && !found; swapped++) {
407 if (!found || a.
from != b.
to) {
408 qCritical(
"Cannot combine coordinate transforms");
417 result.
trans.row(3) << 0.0f, 0.0f, 0.0f, 1.0f;
429 Map<const Vector3f> L(rL);
430 Map<const Vector3f> N(rN);
431 Map<const Vector3f>
R(rR);
433 Vector3f diff1 = N - L;
434 Vector3f diff2 =
R - L;
436 float alpha = diff1.dot(diff2) / diff2.dot(diff2);
437 Vector3f r0 = (1.0f - alpha) * L + alpha *
R;
438 Vector3f ex = diff2.normalized();
439 Vector3f ey = (N - r0).normalized();
440 Vector3f ez = ex.cross(ey);
445 result.
rot().col(0) = ex;
446 result.
rot().col(1) = ey;
447 result.
rot().col(2) = ez;
458 FiffStream::SPtr stream(
new FiffStream(&file));
460 if (!stream->open()) {
464 FiffTag::UPtr t_pTag;
465 for (
int k = 0; k < stream->dir().size(); k++) {
467 if (!stream->read_tag(t_pTag, stream->dir()[k]->pos))
482 qCritical(
"No suitable coordinate transformation found in %s.", name.toUtf8().constData());
506 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
507 qCritical(
"Cannot open %s", name.toUtf8().constData());
511 QTextStream in(&file);
516 while (!in.atEnd() && row < 4) {
517 QString line = in.readLine();
519 int commentIdx = line.indexOf(
'#');
521 line = line.left(commentIdx);
522 line = line.trimmed();
527 QStringList parts = line.simplified().split(
' ', Qt::SkipEmptyParts);
528 if (parts.size() < 4) {
529 qCritical(
"Cannot read the coordinate transformation from %s",
530 name.toUtf8().constData());
533 bool ok1, ok2, ok3, ok4;
534 rot(row, 0) = parts[0].toFloat(&ok1);
535 rot(row, 1) = parts[1].toFloat(&ok2);
536 rot(row, 2) = parts[2].toFloat(&ok3);
537 moveVec[row] = parts[3].toFloat(&ok4) / 1000.0f;
538 if (!ok1 || !ok2 || !ok3 || !ok4) {
539 qCritical(
"Bad floating point number in coordinate transformation");
548 qCritical(
"Cannot read the coordinate transformation from %s",
549 name.toUtf8().constData());
571 qint32* t_pInt32 =
reinterpret_cast<qint32*
>(tag->data());
572 t.
from = t_pInt32[0];
575 float* t_pFloat =
reinterpret_cast<float*
>(tag->data());
578 for (r = 0; r < 3; ++r) {
579 t.
trans(r, 3) = t_pFloat[11 + r];
580 for (c = 0; c < 3; ++c) {
581 t.
trans(r, c) = t_pFloat[2 + count];
585 t.
trans(3, 0) = 0.0f;
586 t.
trans(3, 1) = 0.0f;
587 t.
trans(3, 2) = 0.0f;
588 t.
trans(3, 3) = 1.0f;
591 for (r = 0; r < 3; ++r) {
592 t.
invtrans(r, 3) = t_pFloat[23 + r];
593 for (c = 0; c < 3; ++c) {
594 t.
invtrans(r, c) = t_pFloat[14 + count];
612 FiffTag::UPtr t_pTag;
618 for (
int k = 0; k < node->nent(); ++k) {
619 const FiffDirEntry::SPtr& entry = node->dir[k];
623 if (!stream->read_tag(t_pTag, entry->pos))
638 qWarning(
"No suitable coordinate transformation found");
646 const Eigen::MatrixXf& fromPts,
647 const Eigen::MatrixXf& toPts,
648 const Eigen::VectorXf& w,
651 int np = fromPts.rows();
654 Eigen::Vector3f
from0 = fromPts.colwise().mean();
655 Eigen::Vector3f
to0 = toPts.colwise().mean();
657 Eigen::MatrixXf
fromC = fromPts.rowwise() -
from0.transpose();
658 Eigen::MatrixXf
toC = toPts.rowwise() -
to0.transpose();
663 S =
fromC.transpose() * w.asDiagonal() *
toC;
669 Eigen::JacobiSVD<Eigen::Matrix3f>
svd(
S, Eigen::ComputeFullU | Eigen::ComputeFullV);
670 Eigen::Matrix3f
R =
svd.matrixV() *
svd.matrixU().transpose();
676 for (
int p = 0; p < np; ++p) {
677 Eigen::Vector3f rr =
R * fromPts.row(p).transpose() +
moveVec;
678 float diff = (toPts.row(p).transpose() - rr).norm();
679 if (diff > max_diff) {
680 qWarning(
"Too large difference in matching : %7.1f > %7.1f mm",
681 1000.0f * diff, 1000.0f * max_diff);
constexpr auto FIFFV_MNE_COORD_RAS
constexpr auto FIFFV_COORD_HEAD
constexpr auto FIFFV_COORD_MRI_DISPLAY
constexpr auto FIFFV_MNE_COORD_CTF_HEAD
constexpr auto FIFFV_MNE_COORD_CTF_DEVICE
constexpr auto FIFFV_COORD_MRI_SLICE
constexpr auto FIFFV_COORD_DEVICE
constexpr auto FIFFV_MNE_COORD_MRI_VOXEL
constexpr auto FIFFV_MNE_COORD_MNI_TAL
constexpr auto FIFFV_COORD_UNKNOWN
constexpr auto FIFFV_COORD_MRI
constexpr auto FIFFV_MNE_COORD_FS_TAL_GTZ
constexpr auto FIFFV_COORD_ISOTRAK
constexpr auto FIFFV_COORD_HPI
constexpr auto FIFFV_MNE_COORD_FS_TAL_LTZ
FIFF tag: the 16-byte tag header (kind, type, size, next) plus its decoded payload.
FIFF binary tag-stream layer: wraps a QIODevice to read and write FIFF tags, directories,...
4x4 affine FIFF coordinate transform (FIFF_COORD_TRANS) annotated with source/destination coordinate-...
constexpr auto FIFFT_COORD_TRANS_STRUCT
constexpr auto FIFF_COORD_TRANS
return FiffCoordTrans(from_frame, to_frame, R, moveVec)
Eigen::JacobiSVD< Eigen::Matrix3f > svd(S, Eigen::ComputeFullU|Eigen::ComputeFullV)
Recursive node of the parsed FIFF block tree (FIFFB_* hierarchy with directory entries and children).
FIFF file I/O, in-memory data structures and high-level readers/writers.
Eigen::Matrix< float, 4, 4, Eigen::DontAlign > invtrans
static FiffCoordTrans procrustesAlign(int from_frame, int to_frame, const Eigen::MatrixXf &fromp, const Eigen::MatrixXf &top, const Eigen::VectorXf &w, float max_diff)
static FiffCoordTrans combine(int from, int to, const FiffCoordTrans &t1, const FiffCoordTrans &t2)
static QString frame_name(int frame)
static FiffCoordTrans readTransformFromNode(FiffStream::SPtr &stream, const FiffDirNode::SPtr &node, int from, int to)
void writeToStream(FiffStream *p_pStream)
Writes the transformation to a FIFF stream.
static FiffCoordTrans readMeasTransform(const QString &name)
static FiffCoordTrans readFShead2mriTransform(const QString &name)
Eigen::MatrixX3f apply_inverse_trans(const Eigen::MatrixX3f &rr, bool do_move=true) const
bool write(QIODevice &p_IODevice)
Writes the transformation to file.
static FiffCoordTrans readMriTransform(const QString &name)
static FiffCoordTrans readTransformAscii(const QString &name, int from, int to)
static bool read(QIODevice &p_IODevice, FiffCoordTrans &p_Trans)
FiffCoordTrans inverted() const
Eigen::MatrixX3f apply_trans(const Eigen::MatrixX3f &rr, bool do_move=true) const
float angleTo(Eigen::MatrixX4f mTransDest)
static FiffCoordTrans identity(int from, int to)
static FiffCoordTrans fromCardinalPoints(int from, int to, const float *rL, const float *rN, const float *rR)
float translationTo(Eigen::MatrixX4f mTransDest)
Eigen::Matrix< float, 4, 4, Eigen::DontAlign > trans
static FiffCoordTrans readTransform(const QString &name, int from, int to)
static bool addInverse(FiffCoordTrans &t)
static FiffCoordTrans readFromTag(const std::unique_ptr< FiffTag > &tag)
QSharedPointer< FiffDirNode > SPtr
FIFF tag-stream reader/writer: wraps a QIODevice and exposes typed read_* / write_* methods for every...
QSharedPointer< FiffStream > SPtr
fiff_long_t write_coord_trans(const FiffCoordTrans &trans)
std::unique_ptr< FiffTag > UPtr
Eigen::Matrix< float, 4, 4, Eigen::DontAlign > invtrans
FiffCoordTrans inverted() const
Eigen::Matrix< float, 4, 4, Eigen::DontAlign > trans
static bool addInverse(FiffCoordTrans &t)