1

I would like to know whether is there an easier way to solve my problem rather than use a for loop. So here is the situation:

In general, I would like to gather data points from my sensor (the message is of type Eigen::Vector3d and I can't change this, because it's a huge framework)

Gathered points should be saved in Eigen MatrixXd (in order to process them further as the Matrix in the optimization algorithm), the dimensions apriori of the Matrix are partially unknown, because it depends of me how many measurements I will take (one dimension is 3 because there are x,y,z coordinates)

For the time being, I created a std::vector<Eigen::Vector3d> where I collect points by push_back and after I finished collecting points I would like to convert it to MatrixXd by using the operation Map .

 sensor_input = Eigen::Map<Eigen::MatrixXd>(sensor_input_vector.data(),3,sensor_input_vector.size());

But I have an error and note : no known conversion for argument 1 from Eigen::Matrix<double, 3, 1>* to Eigen::Map<Eigen::Matrix<double, -1, -1>, 0, Eigen::Stride<0, 0> >::PointerArgType {aka double*}

Can you tell me how I could implement this by using a map function?

chtz
  • 17,329
  • 4
  • 26
  • 56
  • What's wrong with using a for loop? – Hong Ooi Apr 13 '18 at 09:22
  • I'm just curious/interested, is there an easier way, and I'm assuming map is more efficient that for loop? – Andrzej Reinke Apr 13 '18 at 09:35
  • 1
    `Map` is the correct way to go here. But you should post an actual [mcve]. `Eigen::Map` is a templated type, so your code above can't compile at all. – chtz Apr 13 '18 at 09:46
  • In other languages, map might be more efficient. In C++, it'll all be the same – Hong Ooi Apr 13 '18 at 09:46
  • 2
    Ok, your mcve was just messed up due to not being formated correctly. You need to write `sensor_input_vector[0].data()` instead of `sensor_input_vector.data()` – chtz Apr 13 '18 at 09:55
  • chtz, it works, but i don't think I understand why – Andrzej Reinke Apr 16 '18 at 10:30
  • @AndrzejReinke If you had added an `@` before my name, I would have gotten a notification. I'll post an answer with some explanations in a moment. – chtz Apr 17 '18 at 11:41

2 Answers2

4

Short answer: You need to write (after making sure that your input is not empty):

sensor_input = Eigen::Map<Eigen::MatrixXd>(sensor_input_vector[0].data(),3,sensor_input_vector.size());

The reason is that Eigen::Map expects a pointer to the underlying Scalar type (in this case double*), whereas std::vector::data() returns a pointer to the first element inside the vector (i.e., an Eigen::Vector3d*).

Now sensor_input_vector[0].data() will give you a pointer to the first (Vector3d) entry of the first element of your std::vector. Alternatively, you could reinterpret_cast like so:

sensor_input = Eigen::Map<Eigen::MatrixXd>(reinterpret_cast<double*>(sensor_input_vector.data()),3,sensor_input_vector.size());

In many cases you can actually avoid copying the data to a Eigen::MatrixXd but instead directly work with the Eigen::Map, and instead of MatrixXd you can use Matrix3Xd to express that it is known at compile time that there are exactly 3 rows:

// creating an Eigen::Map has O(1) cost
Eigen::Map<Eigen::Matrix3Xd> sensor_input_mapped(sensor_input_vector[0].data(),3,sensor_input_vector.size());
// use sensor_input_mapped, the same way you used sensor_input before

You need to make sure that the underlying std::vector will not get re-allocated while sensor_input_mapped is used. Also, changing individual elements of the std::vector will change them in the Map and vice versa.

chtz
  • 17,329
  • 4
  • 26
  • 56
  • You seem to be assuming `sensor_input_vector[0].data() + sensor_input_vector[0].size()` == `sensor_input_vector[1].data()`. Does Eigen guarantee that? – Caleth Apr 17 '18 at 12:23
  • @Caleth Yes, for all fixed sized data types this is guaranteed. – chtz Apr 17 '18 at 12:52
  • @chtz, your answer does not work if `sensor_input_vector` is a VectorXd (not Vector3d). Do you have any suggestions for dynamic size Eigen vector, VectorXd. – John Pekl Dec 05 '21 at 00:48
  • @JohnPekl If you mean `std::vector`, you cannot map that into an `Eigen::Map`, since the data is not continuous. – chtz Dec 05 '21 at 00:55
0

This solution should work:

Eigen::MatrixXd sensor_input = Eigen::MatrixXd::Map(sensor_input_vector[0].data(),
 3, sensor_input_vector.size());

Since your output will be a matrix of 3 x N (N is the number of 3D vectors), you could use the Map function of Eigen::Matrix3Xd too:

Eigen::Matrix3Xd sensor_input = Eigen::Matrix3Xd::Map(sensor_input_vector[0].data(),
 3, sensor_input_vector.size());
biendltb
  • 1,149
  • 1
  • 13
  • 20