Search code examples
c++eigen

Using Stride in Map<Quaternion>


I would like to define a Quaternion on top of the memory of an existing matrix. Let this matrix be

MatrixXd M(4,4);

as an example. I would like my quaternion to be mapped on the second column. Usually I would do

Map<Quaterniond> q (&M(0,1));

Should M be column-major, this would work since the Map would be column-wise.

Now imagine I have a second array N, which is now row-major

Matrix<double, -1, -1, RowMajor> N(4,4);

Now my mapped quaternion

Map<Quaterniond> q (&N(0,1));

would be wrong: the elements of q would be picked up from N row-wise, that is, N(0,1),N(0,2),N(0,3),N(1,0).

With vectors, I have the possibility of specifying the Stride, e.g. the following two lines produce valid results if what I want is to map a 4x1 vector on the second columns of M and N, be them row- or col- major:

Map<const VectorXs, 0, Stride<-1, -1> > vc(&M(0,1), 4, 1, Stride<-1, -1>(M.colStride(),M.rowStride()));
Map<const VectorXs, 0, Stride<-1, -1> > vr(&N(0,1), 4, 1, Stride<-1, -1>(N.colStride(),N.rowStride()));

I have attempted to use the Stride technique to Map<Quaternion> without success. In fact, from the eigen documentation, it seems this is not possible.

The questions are:

  1. Is it possible to use Stride in Map<Quaternion>? How?
  2. If not, why is this not possible?
  3. What workaround or alternative do I have, apart from copying the data to a new Quaternion object?

Solution

  • As of now, this is not possible. This would probably not be too hard to implement, I added a short comment on a related feature request, which would directly allow to write N.row(i).asQuaternion().

    At the moment, you can just copy back and forth between the matrix and the quaternion, which is usually very cheap, maybe even cheaper than handling a pointer and a stride object would be:

    Eigen::Matrix4Xd M; // input/output matrix
    // extract quaternion from M
    Eigen::Quaterniond q(M.row(1).transpose());
    
    // ... do something with q
    
    // copy back quaternion
    M.row(1) = q.coeffs().transpose(); // transposing not necessary (would be done implicitly)
    

    If M does not have 4 columns at compile time, you may need an intermediate Eigen::Vector4d object, or copy the row into an existing Eigen::Quaterniond object, i.e., these alternatives work in this case (copying back stays the same):

    // If M.row(1) is not known at compile time to have 4 elements:
    Eigen::Quaterniond q(Eigen::Vector4d(M.row(1)));
    
    q.coeffs() = M.row(1); // copy row into an existing quaternion