I am looking for a builtin way with the eigen
library to perform coordinate transformations by normal vectors in 2D space.
Mathematically, it's not difficult: Let v = (v_x, v_y)
be a 2D column vector and n = (n_x, n_y)
be a normal vector, then the transformation I am looking for is one by rotational matrix:
v_T = N * v
, with v_T
being the transformed vector and N
being the rotational matrix, which is
| nx, ny |
| -ny, nx |
In my case, the data I need to transform is stored in an Array2Xd
and the normal vectors are stored in a Matrix2Xd
, with each column holding x- and y-component. I need to transform each column in the array by the corresponding normal vector in the matrix.
Currently, I'm doing it like this:
#include <Eigen/Dense>
#include <iostream>
using namespace Eigen;
/* transform a single vector, just for illustration */
Array2d transform_s( const Ref<const Array2d>& v, const Ref<const Vector2d>& n ){
return {
n.dot( v.matrix() ),
-n.y() * v.x() + n.x() * v.y()
};
}
/* transform multiple columns */
Array2Xd transform_m( const Ref<const Array2Xd>& v, const Ref<const Array2Xd>& n ){
Array2Xd transformed ( 2, v.cols() );
/* colwise dot product for first row */
transformed.row(0) = (n * v).colwise().sum();
/* even less elegant calculation for the second row */
transformed.row(1) = n.row(0) * v.row(1) - n.row(1) * v.row(0);
return transformed;
}
int main(){
Array2Xd vals (2, 3);
vals <<
2, 0,-1,
0, 3, 2;
Matrix2Xd n;
n.resizeLike(vals);
n <<
0, 0, 1,
1,-1, 1;
n.colwise().normalize();
std::cout
<< "single column:\n" << transform_s( vals.col(0), n.col(0) )
<< "\nall columns:\n" << transform_m( vals, n.array() )
<< "\n";
return 0;
}
I'm aware of Eigen::Rotation2D
, but it appears to either require an angle or a rotational matrix. I am specifically looking for a way to only provide the normal vectors. Otherwise I need to build the rotational matrices from the normal vectors myself, which doesn't really reduce the complexity on my end.
If there's no way to do this with eigen
, I'll accept that as an answer. In that case, I'd be very happy about a more efficient implementation of what I wrote above.