3

I came across the problem that I want to convert from a std::vector<Eigen::Vector3d> to a std::vector<Eigen::Vector3f>. I was wondering if there is a solution where I dont have to iterate over the points.

// mapping using iteration
std::vector< Eigen::Vector3d> tf{ {1,1,1},{1,1,1},{1,1,1} };
std::vector< Eigen::Vector3f> tf2;
tf2.reserve(tf.size());
std::transform(tf.begin(), tf.end(), std::back_inserter(tf2), [](const Eigen::Vector3d& p) {
    return p.cast<float>();
});

I tried some things like tf.data() and tried to cast that, but I didnt found a solution. I also looked into Eigen::Map<> class, but didnt really find a solution.

Mansoor
  • 2,357
  • 1
  • 17
  • 27
Rob
  • 31
  • 4
  • 4
    Think about what is actually going on here. You're converting a bunch of doubles to a bunch of floats. There is no way to do that without iterating over all the values. You could write the code to do that iteration yourself, or you could find some library function that does the iteration for you, but either way the iteration is happening. If you have some code that works then I would go with it. – john Feb 15 '21 at 08:28
  • `std::transform` can hide iteration. – Kao Feb 15 '21 at 08:33
  • @john Yeah the implementation is like it's posted, what is fine. I thought because its a vector with contiguous data and we know the size of the elements that their is like a magic fnc creation a view or something with a reinterpret_cast but you are totaly right.^^ – Rob Feb 16 '21 at 12:06

2 Answers2

3

I don't think what you are asking is possible. Eigen::Map allows you to construct an Eigen data structure without needing to copy or move, it merely takes a view on existing contiguous data (typically from a std::array or std::vector). The operation you are looking to do, casting from doubles to float, two distinct types with different memory layouts, is an explicit operation. You would be shrinking the size of the vector in half. It is not possible to achieve this by taking a different view on the same data.

Mansoor
  • 2,357
  • 1
  • 17
  • 27
  • Hey thanks for the reply like I posted above I hoped that there is some magic fnc which uses like a reinterpret_cast but I just didn't thought it through. – Rob Feb 16 '21 at 12:09
0

Assuming Vector3d and Vector3f don't introduce any padding (which is true for all compilers which Eigen supports), you could use an Eigen::Map<const Matrix3Xd> and .cast<float>() that into an Eigen::Map<Matrix3Xf> over the destination vector:

std::vector< Eigen::Vector3d> tf{ {1,1,1},{1,1,1},{1,1,1} };
std::vector< Eigen::Vector3f> tf2(tf.size()); // target needs to be actually allocated

Eigen::Matrix3Xf::Map(tf2[0].data(), 3, tf2.size())
  = Eigen::Matrix3Xd::Map(tf[0].data(), 3, tf.size()).cast<float>();

With the upcoming 3.4 branch of Eigen you can also use iterators over the casted-map, like so:

Eigen::Map<Eigen::Matrix3Xd> input(tf[0].data(), 3, tf.size());
std::vector<Eigen::Vector3f> tf2(input.cast<float>().colwise().begin(),
                                 input.cast<float>().colwise().end());
chtz
  • 17,329
  • 4
  • 26
  • 56