項目 | 內容 |
---|---|
這個做業屬於哪一個課程 | 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設計。商量好接口後咱們進行了語音而後一塊兒編程。