2013-03-18 40 views
3

我将两个Eigen3矢量包装在模板LineSegment<T,dim>类中。你可以这样使用它:如何调整Eigen3中的矢量大小

typedef LineSegment<double,2> LineSegment2d; 
typedef LineSegment<double,3> LineSegment3d; 
typedef LineSegment<int,3> LineSegment3i; 

它包含一个模板化的方法来改变组件的尺寸。这里是修剪的定义:

template<typename T,int dim> 
struct LineSegment 
{ 
public: 
    template<int newDim> 
    LineSegment<T,newDim> to() const 
    { 
    Eigen::Matrix<T,newDim,1> newp1; 
    Eigen::Matrix<T,newDim,1> newp2; 

    // TODO initialise newp1 and newp2 from d_p1 and d_p2 

    return LineSegment<T,newDim>(newp1, newp2); 
    } 

    // ... other members ... 

protected: 
    Eigen::Matrix<T,dim,1> d_p1; 
    Eigen::Matrix<T,dim,1> d_p2; 
} 

所以我的问题是,我怎么能撰写的返回值,如上图所示?这应该支持增加和减少维度。

我尝试使用Eigen3 resize(int)方法,但没有看到关于混合矩阵大小的警告,但无法让它工作。

最终,这应该工作:

LineSegment2d ls2d; 
LineSegment3d ls3d = ls2d.to<3>(); // increase dim 
ls2d = ls3d.to<2>();    // decrease dim 

我是比较新的C++模板,并希望得到一些解释,如果这不仅仅是一个API的问题,是关系到模板。

+0

尺寸变化的期望语义是什么?投影到第一个坐标上并在新坐标中用零值展开? – us2012 2013-03-18 17:21:51

+0

@ us2012,该模板通常用作机器人系统的一部分,该系统主要将来自摄像机图像的2D线段转换为其周围地图的3D线段。这种转换是双向的。我可以使用子类而不是typedefs并添加特定的'to3'和'to2'方法,但是想知道是否有这样做的方法。我看到的调整数组大小的唯一例子是动态大小的向量,例如'VectorXd'。 – 2013-03-18 17:30:30

+0

在Eigen2中,我相信你可以使用'.start <3>()',但我可能会误解。 – 2013-03-18 17:34:16

回答

4

首先,本征的resize方法重新分配内存,如果新的单元数量是不一样的旧的,既增长和收缩的时候,所以你会在这种情况下

以下方法使用.head<int>()丢失数据时,这是Eigen3的版本.start<int>(),再加上一些模板编程,这样你就不必检查是否你收缩或增长:

#include <Eigen/Core> 

template <bool COND, int A, int B> 
struct IF 
{ 
    enum { val = A }; 
}; 

template <int A, int B> 
struct IF<false, A, B> 
{ 
    enum { val = B }; 
}; 

template <int A, int B> 
struct MIN : IF<A < B, A, B> 
{ 
}; 

template <typename T,int dim,int newDim> 
Eigen::Matrix<T,newDim,1> to(Eigen::Matrix<T,dim,1> p) 
{ 
    Eigen::Matrix<int,newDim,1> newp = 
    Eigen::Matrix<T,newDim,1>::Zero(); 

    newp.template head< MIN<dim,newDim>::val >() = 
    p.template head< MIN<dim,newDim>::val >(); 

    return newp; 
} 

利用这一点,下面的程序:

#include <iostream> 

int main() 
{ 
    Eigen::Vector2i p_2i(1,2); 
    Eigen::Vector3i p_3i(3,4,5); 

    std::cout << to<int, 2, 3>(p_2i) << std::endl << std::endl; 
    std::cout << to<int, 3, 2>(p_3i) << std::endl << std::endl; 

} 

给出的输出:

1 
2 
0 

3 
4 
+0

我以为我最终可能会学习关于模板的东西:)非常感谢。 – 2013-03-18 19:16:36

0

为了完整起见,这里的解决方案原位,使用@sgvd's technique这完全做的工作:

template<typename T,int dim> 
struct LineSegment 
{ 
public: 
    template<int newDim> 
    LineSegment<T,newDim> to() const 
    { 
    Eigen::Matrix<T,newDim,1> newp1; 
    Eigen::Matrix<T,newDim,1> newp2; 

    newp1.template head< MIN<dim,newDim>::val >() = d_p1.template head< MIN<dim,newDim>::val >(); 
    newp2.template head< MIN<dim,newDim>::val >() = d_p2.template head< MIN<dim,newDim>::val >(); 

    return LineSegment<T,newDim>(newp1, newp2); 
    } 

    // ... other members ... 

protected: 
    Eigen::Matrix<T,dim,1> d_p1; 
    Eigen::Matrix<T,dim,1> d_p2; 

private: 
    template <bool COND, int A, int B> 
    struct IF 
    { 
    enum { val = A }; 
    }; 

    template <int A, int B> 
    struct IF<false, A, B> 
    { 
    enum { val = B }; 
    }; 

    template <int A, int B> 
    struct MIN : IF<A < B, A, B> 
    {}; 
} 

这通过单元测试:

TEST (LineSegmentTests, to) 
{ 
    EXPECT_EQ (LineSegment3i(Vector3i(1,2,0), Vector3i(3,4,0)), 
       LineSegment2i(Vector2i(1,2), Vector2i(3,4) ).to<3>()); 

    EXPECT_EQ (LineSegment2i(Vector2i(1,2), Vector2i(4,5)), 
       LineSegment3i(Vector3i(1,2,3), Vector3i(4,5,6)).to<2>()); 

    EXPECT_EQ (LineSegment3i(Vector3i(1,2,3), Vector3i(4,5,6)), 
       LineSegment3i(Vector3i(1,2,3), Vector3i(4,5,6)).to<3>()); 
}