《實時控制軟件設計》做業一:Eigen庫的使用

做業內容及要求這裏
代碼repohtml

1. 定義數據類型

題目要求實現對平面圖形的一系列圖形學操做。平面圖形能夠表示爲其全部頂點的有序連線,對圖形的操做能夠分解爲對其全部頂點依次應用同一操做。
以「頂點序列表示圖形」的思路,定義GeoElement類型,用於表示包括點、線、多邊形的平面圖形元素,使用STL中的動態數組vector類實現。其定義以下:ios

typedef std::vector<Vector2d> GeoElement;

測試使用GeoElement建立一條直線並輸出:git

//commit 6372dba /main.cpp
#include <iostream>
#include <vector>
#include <Eigen/Dense>
using namespace Eigen;

int main() {
    typedef std::vector<Vector2d> GeoElement;
    GeoElement line;
    line.push_back(Vector2d(2, 5));
    line.push_back(Vector2d(3, 1));
    std::cout<<"line:"<<std::endl<<"("<<RowVector2d(line[0])<<"), ("<<RowVector2d(line[1])<<")"<<std::endl;
    return 0;
}

輸出結果:github

line:
(2 5), (3 1)

2.實現move指令

move指令,即圖形的平移操做,是最簡單的圖形操做,也是圖形繞任意點旋轉的基礎。
在這一步,咱們建立了GeoUtils類,將各個操做指令做爲其靜態函數,並將上一步定義的GeoElement類型也做爲其成員,加強代碼的組織。
move指令的實現以下:數組

//commit bd6457b /GeoUtils.cpp
GeoUtils::GeoElement GeoUtils::move(Vector2d movement, GeoUtils::GeoElement elmt)
{
    GeoUtils::GeoElement res;
    GeoUtils::GeoElement::iterator t;
    for(t=elmt.begin(); t!=elmt.end(); t++)
    {
        res.push_back(*t+movement);
    }
    return res;
}

實現的方式就是將elmt中的每一個點依次與移動向量作加法,獲得的便是移動後的圖形中對應點的座標。
測試代碼以下:bash

//commit 9d4515e /main.cpp
#include <iostream>
#include <vector>
#include <Eigen/Dense>
#include "GeoUtils.h"
using namespace Eigen;

int main() {
    GeoUtils::GeoElement triangle;
    triangle.push_back(Vector2d(2, 5));
    triangle.push_back(Vector2d(3, 1));
    triangle.push_back(Vector2d(2, 9));
    Vector2d movement(3, -5);
    std::cout<<"original triangle:"<<std::endl;
    GeoUtils::printElement(triangle);
    std::cout<<"movement vector:"<<std::endl<<movement<<std::endl;
    std::cout<<"moved triangle:"<<std::endl;
    GeoUtils::printElement(GeoUtils::move(movement, triangle));
    return 0;
}

輸出結果:函數

original triangle:
(2 5) (3 1) (2 9) 
movement vector:
 3
-5
moved triangle:
(5 0) ( 6 -4) (5 4)

3.實現rotate指令

要求中提到rotate指令的功能是繞原點逆時針旋轉。點繞原點逆時針旋轉的變換以下:
$$ \begin{bmatrix} x' \\ y' \end{bmatrix} = \begin{bmatrix} cos\theta & -sin\theta \\ sin\theta & cos\theta \end{bmatrix} \begin{bmatrix} x \\ y \end{bmatrix} $$
其中(x,y)爲變換前的座標,(x',y')爲變換後的座標,θ爲旋轉的角度。
只需將圖形逐點按此式變換便可:測試

//commit 7c2c3f8 /GeoUtils.cpp
GeoUtils::GeoElement GeoUtils::rotate(double theta, GeoElement elmt)
{
    const double PI=3.14159265;
    double rad=theta*PI/180;
    Matrix2d R;
    R<<cos(rad), -sin(rad), sin(rad), cos(rad);
    GeoElement res;
    GeoElement::iterator t;
    for(t=elmt.begin(); t!=elmt.end(); t++)
    {
        res.push_back(R*(*t));
    }
    return res;
}

測試代碼:spa

//commit 7c2c3f8 /main.cpp
#include <iostream>
#include <vector>
#include <Eigen/Dense>
#include "GeoUtils.h"
using namespace Eigen;

int main() {
    GeoUtils::GeoElement triangle;
    triangle.push_back(Vector2d(2, 5));
    triangle.push_back(Vector2d(3, 1));
    triangle.push_back(Vector2d(2, 9));
    double angle=90;
    std::cout<<"original triangle:"<<std::endl;
    GeoUtils::printElement(triangle);
    std::cout<<"rotate angle: "<<angle<<std::endl;
    std::cout<<"rotated triangle:"<<std::endl;
    GeoUtils::printElement(GeoUtils::rotate(angle, triangle));
    return 0;
}

輸出結果:設計

original triangle:
(2 5) (3 1) (2 9) 
rotate angle: 90
rotated triangle:
(-5  2) (-1  3) (-9  2)

moverotate命令組合便可實現繞任意點旋轉的變換,命名爲rotatep(rotating about a point)。實現以下:

GeoUtils::GeoElement GeoUtils::rotatep(double theta, Vector2d point, GeoElement elmt)
{
    return move(point, rotate(theta, move(-point, elmt)));
}

測試代碼及結果再也不贅述。

TODO:

  1. 讀取和解析用戶指令

  2. 設計文件格式並實現解析器

  3. GUI的開發

相關文章
相關標籤/搜索