2013-03-18 142 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>()); 
}