2
votes

I find the design of functions with Eigen objects as parameters cumbersome. While the information in the Eigen Documentation is helpful, it suggests an awkward approach for the template arguments. Suppose, we want to write a geometric routine like a line-plane-intersection. A simple and transparent approach would be:

template<typename _Tp> 
bool planeLineIntersect(const Eigen::Matrix<_Tp, 3, 1>& planePoint, 
                        const Eigen::Matrix<_Tp, 3, 1>& planeNormal, 
                        const Eigen::Matrix<_Tp, 3, 1>& linePoint, 
                        const Eigen::Matrix<_Tp, 3, 1>& lineDir,
                        Eigen::Matrix<_Tp, 3, 1>& intersectionPoint)

This looks relatively pleasing and someone that looks at this can learn that every parameter shall be a 3D vector of the same type. However, directly, this does not allow for Eigen expressions of any kind (we would have to call Eigen::Matrix constructors for every expression, that we use). So if expressions are used with this, we need to create unnecessary temporaries.

The suggested solution is:

template<typename Derived1, typename Derived2, typename Derived3, typename Derived4, typename Derived5> 
bool planeLineIntersect(const Eigen::MatrixBase<Derived1>& planePoint, 
                        const Eigen::MatrixBase<Derived2>& planeNormal, 
                        const Eigen::MatrixBase<Derived3>& linePoint, 
                        const Eigen::MatrixBase<Derived4>& lineDir,
                        const Eigen::MatrixBase<Derived5>& intersectionPoint)

This does not reveal anything about the matrices that are expected, nor which parameters are used for input and output, as we have to const-cast the intersectionPoint to allow for expressions in output parameters. As I understand it, this is the only way to allow for Eigen expressions in all function parameters. Despite the unelegant expression support, the first snippet still seems more likable to me.

My Questions:

  1. Would you consider the second code snippet the best solution for this example?
  2. Do you ever use the const-cast solution for output parameters or do you think it is not worth the loss in transparency?
  3. What guidelines/best practices do you use for Eigen function writing?
1

1 Answers

1
votes

For such small fixed size objects, I'd not bother much and go with the first solution.

It's rarely a good approach to have output function parameters. In you particular case, one approach would be to create a PlaneLineIntersection class whose ctor would take a plane and a line, stores the result of the intersection and then provides accessors to query the result of the computation (no intersection, is it a point, a line).

BTW, have you noticed the HyperPlane and ParametrizedLine class of the Eigen/Geometry module? The ParametrizedLine class has an intersectionPoint member with an HyperPlane (though it's limited because it assumes the intersection does exist and it is a point).