题目要求实现对平面图形的一系列图形学操做。平面图形能够表示为其全部顶点的有序连线,对图形的操做能够分解为对其全部顶点依次应用同一操做。
以“顶点序列表示图形”的思路,定义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)
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)
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)
将move
和rotate
命令组合便可实现绕任意点旋转的变换,命名为rotatep
(rotating about a point)。实现以下:
GeoUtils::GeoElement GeoUtils::rotatep(double theta, Vector2d point, GeoElement elmt) { return move(point, rotate(theta, move(-point, elmt))); }
测试代码及结果再也不赘述。
读取和解析用户指令
设计文件格式并实现解析器
GUI的开发