Best way to convert an Eigen Vector4 type to Vector3?
Asked Answered
B

3

18

I want to extract the three first values of a Vector4 type in Eigen, into a Vector3 type. So far I am doing it in a for-loop. Is there a smarter way to do it?

Balkhash answered 3/8, 2014 at 12:33 Comment(0)
M
27

The .head() member function returns the first n elements of a vector. If n is a compile-time constant, then you can use the templated variant (as in the code example below) and the Eigen library will automatically unroll the loop.

Eigen::Vector4f vec4;
// initialize vec4
Eigen::Vector3f vec3 = vec4.head<3>();

In the Eigen documentation, see Block operations for an introduction to similar operations for extracting parts of vectors and matrices, and DenseBase::head() for the specific function.

Mccracken answered 3/8, 2014 at 20:36 Comment(0)
P
7

The answer of @Jitse Niesen is correct. Maybe this should be a comment on the original question, but I found this question because I had some confusion about Eigen. In case the original questioner, or some future reader has the same confusion, I wanted to provide some additional explanation.

If the goal is to transform 3d (“position”) vectors by a 4x4 homogeneous transformation matrix, as is common in 3d graphics (e.g. OpenGL etc), then Eigen provides a cleaner way to do that with its Transform template class, often represented as the concrete classes Affine3f or Affine3d (as tersely described here). So while you can write such a transform like this:

Eigen::Matrix4f transform;      // your 4x4 homogeneous transformation
Eigen::Vector3f input;          // your input
Eigen::Vector4f input_temp;
input_temp << input, 1;         // input padded with w=1 for 4d homogeneous space
Eigen::Vector4f output_temp = transform * input_temp;
Eigen::Vector3f output = output_temp.head<3>() / output_temp.w(); // output in 3d

You can more concisely write it like this:

Eigen::Affine3f transform;      // your 4x4 homogeneous transformation
Eigen::Vector3f input;          // your input
Eigen::Vector3f output = transform * input;

That is: an Eigen::Affine3f is a 4x4 homogeneous transformation that maps from 3d to 3d.

Puryear answered 25/3, 2018 at 15:48 Comment(3)
"maps from 3d to 3d": Did you mean to say "from 3D to 2D"? Because otherwise, your two code snippets are not identical. I can't figure out from the Eigen documentation whether Affine3 performs a division by 'w', as is needed for projecting from 3D to 2D.Capacious
Also, to be fair to the first code snippet, it can be simplified a lot by just writing Eigen::Vector4f output_temp = transform * input.homogenous();. You still need one extra line / temporary though - but personally, I prefer to see an explicit division by w in the code.Capacious
@Ela782: Well it has been a while (4 years) but I’m pretty sure I meant “3d to 3d.” Where you have 3d data, you want to transform it by a 4x4 matrix (combinations of scale, rotate, translate, shear — where the last column is [0,0,0,1]) to produced transformed 3d data.Puryear
A
0

Yeah, because you know the size is static (3 elements) you should unroll the loop and copy them explicitly. This optimization might be performed by the compiler already, but it can't hurt to do it yourself just in case.

Annmaria answered 3/8, 2014 at 13:22 Comment(3)
The solution based on vec4.head<3>() explicitly unrolls the loop for you using meta programming techniques.Olga
For the record, it can hurt - the code will become much harder to read and maintain, all for a performance improvement that's very likely to be 0 and guaranteed to be tiny. In general, trust the experts working on compilers to be able to do these kinds of simple optimizations better than you can.Marvin
In this case no it cannot hurt. Any developer who cannot understand code that explicitly copies 3 elements of a vector has no business working on linear algebra code.Annmaria

© 2022 - 2024 — McMap. All rights reserved.