项目 | 内容 |
---|---|
这个做业属于哪一个课程 | 2020计算机学院软件工程(罗杰 任健) |
这个做业的要求在哪里 | 结队项目做业 |
教学班级 | 006 |
项目地址 | 结队项目做业 |
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 100 | 100 |
· Estimate | · 估计这个任务须要多少时间 | 2500 | 3000 |
Development | 开发 | 2000 | 2000 |
· Analysis | · 需求分析 (包括学习新技术) | 500 | 1000 |
· Design Spec | · 生成设计文档 | 300 | 300 |
· Design Review | · 设计复审 (和同事审核设计文档) | 100 | 100 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 35 |
· Design | · 具体设计 | 500 | 800 |
· Coding | · 具体编码 | 1000 | 1000 |
· Code Review | · 代码复审 | 100 | 100 |
· Test | · 测试(自我测试,修改代码,提交修改) | 200 | 200 |
Reporting | 报告 | ||
· Test Report | · 测试报告 | 100 | 100 |
· Size Measurement | · 计算工做量 | 100 | 100 |
· Postmortem & Process Improvement Plan | · 过后总结, 并提出过程改进计划 | 50 | 50 |
合计 | 2530 | 2835 |
信息隐藏的设计意图为将数据进行封装,不让外部访问,保证安全。本次做业将不一样的数据结构封装成为不一样的类,可是对于交点的求解未封装进类中而是采用了全局函数的形式,具体细节在后文介绍。html
不一样的类只暴露相应的接口,接口的设计是为了让可以很好的铆接程序的各个部分,所谓的面向接口编程就是只关注接口的参数和返回值,至于接口内部实现当作黑盒并不关心。咱们本次结对做业的主要接口为5个全局变量,前端与后端的主要交互手段为5个存储着交点、直线、线段、射线、圆的容器,前端负责绘图,后端负责计算,以此达到一个较好的铆接。原本想利用重载,可是后来又从新编写了不一样的函数名,见名知义,对传入参数的不一样,使用不一样的计算函数。具体设计会在后文介绍。前端
咱们本次做业采用了先后端分离的模式,后端负责计算数据,前端负责展现,可是因为未和其余队伍造成一个良好的接口匹配,因此没法向外部体现这一点。可是在结对过程当中咱们是分工明确的,后端编写者不知道前端编写者具体的逻辑,只知道提供接口便可,前端编写者亦然。node
本次做业一共使用了6个类,其中1个类为UI类,剩下5个类为图形类,分别为点、直线、射线、线段、圆。git
函数一共分为5大类,函数的交互方法以下图(箭头为调用关系):
github
算法关键:算法
咱们算法的关键在于,计算交点的方法时间复杂度为:\(O(n^2)\),利用map并重载运算符保证点的惟一性,最后使用先后端分离的方法,前端接受请求,后端处理请求并返回给前端相应数据最终实现需求。编程
实体关系:
后端
其中带有箭头之间的实体表明具备交互,如图所示,前端想要获取后端数据必须经过后端提供的接口。安全
在2000条测试数据下:read_file()函数为总的计算花费,而originGeo()函数和show()函数分别是图形的添加和图形的绘制,本次做业的性能瓶颈为图像的绘制,由于采用第三方库的缘故,因此很难进行更进一步的优化。
微信
能够看到图像绘制占用了整体CPU时间的31.8%
本次编程虽然没有将合同文本化,可是仍是作了较多的交流好比固定接口,如下是微信交流确认接口的界面
后来的接口交流补充文件截图:
异常处理模块咱们也采用了先后端分离的模式,分为几种情形:
输入文件为
效果如图所示:
输入样例同上
输出为:
输入数据:
输出结果:
输出结果:
咱们的界面设计使用了QT库,仍是用了QCustomplot这样一个第三方库,部分代码借鉴了Qcustomplot的样例模板,界面布局以下图:
大部分功能使用了按键与槽函数的结合,代码举例以下:
//可拖动 customPlot->setInteraction(QCP::iRangeDrag, true); //可缩放 customPlot->setInteraction(QCP::iRangeZoom, true); //曲线可选 customPlot->setInteraction(QCP::iSelectPlottables, true); //曲线 ctrl 多选 customPlot->setInteraction(QCP::iMultiSelect, true); //坐标轴可选 customPlot->setInteraction(QCP::iSelectAxes, true); //图例可选 customPlot->setInteraction(QCP::iSelectLegend, true); // 选中轴时上下轴一块儿被选中 connect(customPlot, SIGNAL(selectionChangedByUser()), this,SLOT(selectionChanged())); // 选中轴时,鼠标拖动智能移动一边的轴,滚轮也是同样 connect(customPlot, SIGNAL(mousePress(QMouseEvent*)), this,SLOT(mousePress())); connect(customPlot, SIGNAL(mouseWheel(QWheelEvent*)), this,SLOT(mouseWheel())); //多选框切换时,直线输入切换成圆输入 connect(ui->comboBox,SIGNAL(activated(int)),this,SLOT(switchGeo())); connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(addGeo())); //文件输入 connect(ui->pushButton_2, SIGNAL(clicked()), this,SLOT(fileInput()));
前端后端对接使用了5个容器:
map <node, int>* nodes; vector<line>* lines; vector<rays>* rayss; vector<lise>* lises; vector<Cycle>* cycles;
5个指针指向后端的全局变量,获得计算出的交点、直线、圆的全部信息,绘制图形的代码以下:
void MainWindow::originGeo() { //画交点 QVector<double> nodex; QVector<double> nodey; for (map <node, int>::iterator iter = (*nodes).begin(); iter != (*nodes).end(); iter++) { node temp = iter->first; double x = temp.getX(); double y = temp.getY(); nodex.push_back(x); nodey.push_back(y); } QCPGraph* graph = customPlot->addGraph(); graph->setData(nodex, nodey); graph->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ScatterShape::ssDisc, 5)); QPen graphPen; graphPen.setColor(QColor(255,255,255)); graphPen.setWidthF(rand() / (double)RAND_MAX * 2 + 1); graph->setPen(graphPen); graph->setName("交点集合"); int cnt = (*nodes).size(); ui->lineEdit_8->setText(QString::number(cnt)); if (cnt >= 20) { customPlot->legend->setVisible(true); } //---------------------------------------- //画直线 int linesize = (*lines).size(); for (int i = 0; i < linesize; i++) { line l = (*lines)[i]; int x1 = l.getNode1().getX(); int y1 = l.getNode1().getY(); int x2 = l.getNode2().getX(); int y2 = l.getNode2().getY(); if (l.getExitK()) { double k = l.getK(); double b = (-1) * l.getC() / l.getB(); for (int i = 0; i < 10000; i++) { (*valueY)[i] = k * (*indexX)[i] + b; } QCPGraph* graph = customPlot->addGraph(); graph->setData(*indexX, *valueY); } else { //斜率不存在时不支持画图 continue; } QPen graphPen; graphPen.setColor(QColor(rand() % 245 + 10, rand() % 245 + 10, rand() % 245 + 10)); graphPen.setWidthF(rand() / (double)RAND_MAX * 2 + 1); customPlot->graph()->setPen(graphPen); //customPlot->graph()->setName("line(编号:" + QString::number(customPlot->graphCount()) + ")"); const QString name = "L " + QString::number(x1) + " " + QString::number(y1) + " " + QString::number(x2) + " " + QString::number(y2); customPlot->graph()->setName(name); } //---------------------------------------- //画射线 int raysize = (*rayss).size(); for (int i = 0; i < raysize; i++) { rays ray = (*rayss)[i]; int x1 = ray.getStart().getX(); int y1 = ray.getStart().getY(); int x2 = ray.getN().getX(); int y2 = ray.getN().getY(); if (ray.getExitK()) { double k = ray.getK(); double b = (-1) * ray.getC() / ray.getB(); QVector<double> fx; QVector<double> fy; for (int i = 0; i < 10000; i++) { (*valueY)[i] = k * (*indexX)[i] + b; node tempnode((*indexX)[i], (*valueY)[i]); if (ray.judge(tempnode)) { fx.push_back((*indexX)[i]); fy.push_back((*valueY)[i]); } } QCPGraph* graph = customPlot->addGraph(); graph->setData(fx, fy); } else { //斜率不存在时不支持画图 continue; } QPen graphPen; graphPen.setColor(QColor(rand() % 245 + 10, rand() % 245 + 10, rand() % 245 + 10)); graphPen.setWidthF(rand() / (double)RAND_MAX * 2 + 1); customPlot->graph()->setPen(graphPen); const QString name = "R " + QString::number(x1) + " " + QString::number(y1) + " " + QString::number(x2) + " " + QString::number(y2); //customPlot->graph()->setName("ray(编号:" + QString::number(customPlot->graphCount()) + ")"); customPlot->graph()->setName(name); } //---------------------------------------- //画线段 int lisesize = (*lises).size(); for (int i = 0; i < lisesize; i++) { lise ls = (*lises)[i]; int x1 = ls.getNode1().getX(); int y1 = ls.getNode1().getY(); int x2 = ls.getNode2().getX(); int y2 = ls.getNode2().getY(); if (ls.getExitK()) { double k = ls.getK(); double b = (-1) * ls.getC() / ls.getB(); QVector<double> fx; QVector<double> fy; for (int i = 0; i < 10000; i++) { (*valueY)[i] = k * (*indexX)[i] + b; node tempnode((*indexX)[i], (*valueY)[i]); if (ls.judge(tempnode)) { fx.push_back((*indexX)[i]); fy.push_back((*valueY)[i]); } } QCPGraph* graph = customPlot->addGraph(); graph->setData(fx, fy); } else { //斜率不存在时不支持画图 continue; } QPen graphPen; graphPen.setColor(QColor(rand() % 245 + 10, rand() % 245 + 10, rand() % 245 + 10)); graphPen.setWidthF(rand() / (double)RAND_MAX * 2 + 1); customPlot->graph()->setPen(graphPen); const QString name = "S " + QString::number(x1) + " " + QString::number(y1) + " " + QString::number(x2) + " " + QString::number(y2); customPlot->graph()->setName(name); } //---------------------------------------- //画圆 int circlesize = (*cycles).size(); valueY1 = new QVector<double>(10000); for (int i = 0; i < circlesize; i++) { Cycle c = (*cycles)[i]; int x = c.getC().getX(); int y = c.getC().getY(); int r = c.getR(); const QString name = "C " + QString::number(x) + " " + QString::number(y) + " " + QString::number(r); r = r * r; double temp = 0; double temp1 = 0; for (int i = 0; i < 10000; i++) { temp = ((*indexX)[i] - x) * ((*indexX)[i] - x); temp1 = sqrt(r - temp); (*valueY)[i] = y + temp1; (*valueY1)[i] = y - temp1; } //int cnt = customPlot->graphCount(); customPlot->addGraph(); customPlot->graph()->setData(*indexX, *valueY); customPlot->graph()->setName(name); customPlot->addGraph(); customPlot->graph()->setData(*indexX, *valueY1); customPlot->graph()->setName(name); } customPlot->replot(); return; }
功能包括:
结对过程当中咱们进行了详细的分工,黎正宇负责后端逻辑,我负责前端UI设计。商量好接口后咱们进行了语音而后一块儿编程。