github連接 html
項目 | 內容 |
---|---|
這個做業屬於哪一個課程 | https://edu.cnblogs.com/campus/buaa/BUAA_SE_2020_LJ |
這個做業的要求在哪裏 | https://edu.cnblogs.com/campus/buaa/BUAA_SE_2020_LJ/homework/10466) |
我在這個課程的目標是 | 提高軟件開發能力 |
這個做業在哪一個具體方面幫助我實現目標 | 提高了我的編程能力, 測試和提高代碼性能的能力 |
PSP2.1 | Personal SoftWare Process Stages | 預計耗時 | 實際耗時 |
---|---|---|---|
Planning | 計劃 | 120 | 60 |
Estimte | 估計這個任務須要多少時間 | 1800 | 1700 |
Development | 開發 | 1100 | 1000 |
Analysis | 需求分析 | 0 | 0 |
Desing Spaec | 生成設計文檔 | 100 | 40 |
Design Review | 設計複審 | 100 | 10 |
Coding Standard | 代碼規範 | 0 | 0 |
Design | 具體設計 | 60 | 40 |
Coding | 具體編碼 | 1100 | 180 |
Code Review | 代碼複審 | 60 | 60 |
Test | 測試 | 180 | 180 |
Reporting | 報告 | 100 | 120 |
Test Report | 測試報告 | 0 | 0 |
Size Measurement | 計算工做量 | 5 | 0 |
Postmortem & Process Improvement | 過後總結 | 60 | 50 |
- | 合計 | 1800 | 1700 |
通過查閱資料和學習, 我瞭解到在接口設計中有經常使用的一些原則, 本次做業的設計中, 咱們用到了這些原則。node
單一職責原則c++
Single Responsibility Principle: There shuld never be more than one reason for class to changegit
單一職責原則要求一個接口, 一個功能, 若是在private 方法和public接口中, 改動過多, 那麼容易引發錯誤。 在結對編程的設計中, 計算模塊裏咱們儘可能保證一個函數只作一個事情, 好比Line Circle Point分出三個類, 每一個求交點的函數只處理一種類型等。github
里氏替換原則算法
Liskov Substitution Principle: Functions that use pointers or references to base classed must be able to use objecsts of derived classes without knowing it編程
這一法則是多態的體現, 全部父指針的使用點均可以用子指針, 這要求了子類只擴展父類, 可是不能夠用在覆寫父類函數的時候讓函數的應用範圍減小。 在最初的版本中, 咱們採用了Line Circle繼承父類的方式實現, 後來發現這種繼承影響性能, 就放棄了繼承。windows
依賴倒置原則數據結構
依賴倒轉原則是TDD測試驅動開發的體現, 要求高層模塊不依賴特定的底層模塊, 而是依賴其抽象, 這要求編程者提早想好接口。架構
接口隔離原則
clients should not be forced to depend upon interfacess that they don't use
保證接口單一, 不要過於臃腫, 在計算模塊和UI模塊的對接時, 咱們儘可能細化接口, 讓模塊的每一個按鈕對應了恰好一個接口, 同時接口之間的功能達到了隔離。
迪米特法則
law of Demeter: least knowledge
loose coupling: Loose coupling means they mostly independent
這一原則要求兩個類之間要低耦合, 達到loose coupling, 一個類不須要知道另外一個類是怎麼實現的, 更不須要由於一個類內部代碼的修改二更改本身的方法。 在咱們的結對編程中, 爲了實現接口的高效對接, 對於接口進行和抽象和封裝
共設置4個類,分別爲表示直線、射線、線段的Line
類(經過成員m_type
區分),表示圓的Circle
類,表示交點的Node
類,以及負責維護幾何對象、計算交點及輸出結果的主類Intersect
類。幾何對象類的成員包含構造參數以及爲求解交點時減小計算量而預存的衍生量。此外,Line
類還包含一個判斷輸入的交點是否在該線上的online
成員函數。
主類Intersect
在實例化後能夠經過addGeoFromFile
函數從目標路徑文件中讀入幾何對象,也能夠經過addGeoByString
函數由指定格式的字符串添加幾何對象。還能夠經過removeGeoByString
函數刪除容器中和指定格式的字符串所表示的幾何對象相同的幾何對象。主類提供CalculateIntersections
函數用於觸發交點的計算,這個函數經過調用相應的交點計算函數計算每兩個幾何體所造成的交點並保存在容器中。在交點計算完畢後能夠經過GetIntersectionNumber
函數獲得交點個數,或使用GetGeoObjects
和GetIntersections
函數輸出幾何對象的具體信息,也可經過ViewIntersections
函數打印交點至標準輸出以快速調試。
主類在實例化時生成存放幾何對象及交點的容器,並在後續過程當中不斷更新。UML圖以下:
交點的計算根據代數或幾何方法實現。其中,線間交點的求解依賴行列式,較爲工整規範;線圓交點的求解經過將圓心平移至原點,簡潔地計算出交點後再平移回去的方法實現(可視爲座標系的線性變換);圓圓的交點則經過相交部分的三角關係求解。具體以下:
對於\(L_1\{(x_1,y_1), (x_2,y_2)\},L_2\{(x_3,y_3),(x_4,y_4)\}\),交點爲:
判據爲\(\Delta= \left|\begin{array}{} x_1-x_2 & y_1-y_2\\ x_3-x_4 & y_3-y_4 \end{array}\right|\),有:
爲減小計算,讀入直線時預存\(x_1-x_2,y_1-y_2\)和\(\left|\begin{array}{}x_1 & x_2\\y_1 & y_2\end{array}\right|\)。
對於\(L\{(x_1,y_1),(x_2,y_2)\},C\{(x_c,y_c),r\}\),交點爲:
其中:
判據爲\(\Delta=r^2{d_r}^2-D^2\),有:
爲減小計算,讀入圓時預存\(r^2\)。
對於\(C_1\{(x_1,y_1),r_1\},C_2\{(x_2,y_2),r_2\}\),交點爲:
其中:
判據爲\(\Delta={r_1}^2-a^2\),有:
參考資料:
https://mathworld.wolfram.com/Line-LineIntersection.html
https://mathworld.wolfram.com/Circle-LineIntersection.html
http://paulbourke.net/geometry/circlesphere/
對射線和線段的支持,在不改變求交點算法的前提下實現。在求出交點後由Line
對象使用成員函數online
根據m_type
判斷交點是否在該線上,決定是否將其加入交點集m_allIntersections
中。其中:
爲節省計算,在構造線段時預存橫縱座標的最值。
特別地,須要額外考慮非直線的線型對象之間的相交。當其判據\(\Delta\)爲零時(向量平行)仍可能相交。若數據合法,則只可能相交於端點處,所以予以特判。
將計算模塊封裝爲動態鏈接庫後,對外接口有三。一爲readFile
函數,用於從文件中輸入幾何對象;二爲addGeometryObject
函數,用於經過字符串輸入單個幾何對象;三爲getResult
函數,用於觸發交點的計算並返回一個由包含全部幾何對象描述串的列表和由全部交點構成的列表所組成的元組,形如pair<vector<string>, vector<Point>>
。
UML圖是用來表示類之間設計關係的圖表, 主要有如下五種關係
用UML圖表示計算模塊的關係以下圖所示
一共用三個類來存數據, Line, Circle, Node(點), Intersect裏面聚合了這三種數據, 進行一系列運算
記錄在改進計算模塊性能上所花費的時間,描述你改進的思路,並展現一張性能分析圖(由VS 2015/2017的性能分析工具自動生成),並展現你程序中消耗最大的函數。(3')
經過隨機生成的數據進行性能測試,佔用CPU時間最多的子函數每每是與交點存儲所用數據結構相關的函數,如選用unordered_set
時哈希值的計算,選用set
時元素之間的比較等。所以交點存儲數據結構的選擇對性能的提高十分關鍵,備選方案及可能的問題以下:
unordered_set
:須要考慮哈希桶的數量(根據幾何對象數目肯定)和哈希函數的設計。set
:雖然紅黑樹的更新較哈希錶慢,但不存在rehash的問題。vector
+sort
+unique
:重複的交點較多時會超過內存限制,須要隨時檢測去重。所以最終的問題在於在給定的數據條件下哪一種數據結構更優。通過比較,採用了unordered_set
,並在Intersect
類初始化時使用reserve
函數預設哈希桶數量爲\(5000000\)以免rehash開銷。在隨機生成的\(2000\)個幾何對象的測試中(交點數在1M以上)性能分析圖以下:
可見,CPU佔用率最高的函數爲存放交點的unordered_set
調用的equal_to
函數。這說明哈希值的碰撞較多,能夠考慮優化哈希值的計算。查閱資料後選取了較爲合適的:
須要注意的是,浮點數的哈希會致使在精度範圍內相等的數被哈希至不一樣哈希桶,致使重複計算。針對這個問題將哈希函數修改成:
參考資料:
https://stackoverflow.com/questions/16792751/hashmap-for-2d3d-coordinates-i-e-vector-of-doubles
https://www.zhihu.com/question/52368555
經過查閱如下材料,修改了原始程序中可能致使性能降低的代碼,改進包含:
new
來給指針分配堆空間,減少內存管理開銷。emplace
系列函數向容器中插入元素,避免push
的拷貝開銷。http://www.javashuo.com/article/p-hvmxpkiy-nn.html
https://blog.csdn.net/nodeman/article/details/80771789
https://blog.csdn.net/p942005405/article/details/84764104
Design By Contract: It prescribes that software designers should define formal, precise and verifiable interface specifications for software components, which extend the ordinary definition of abstract data types with preconditions, postconditions and invariants.
在上學期的OO中, 我瞭解到和約設計須要定義如下的條件
因爲對於每一個函數用和約設計過於複雜, 並不實用, 所以咱們對於模塊進行和約設計, 各自保證計算模塊和UI模塊的正確性, 獨立測試。
展現出項目部分單元測試代碼,並說明測試的函數,構造測試數據的思路。並將單元測試獲得的測試覆蓋率截圖,發表在博客中。要求整體覆蓋率到 90% 以上,不然單元測試部分視做無效。(6')
本次單元測試繼承了上次的測試代碼,放入OldTest
類中。其包含三個TEST_METHOD
,分別在僅有直線、僅有圓以及線圓混合的狀況下針對幾何對象之間的相離、相切、相交、共交點等狀況各測試\(5\)個樣例。其中測試直線的部分以下:
新增功能的測試則包含在NewTest
類中,其下轄三個TEST_METHOD
針對射線和線段之間的位置關係及特殊狀況(平行交於端點)共測試了\(14\)個樣例。其中測試線段的部分以下:
此外還設置了精度和溢出測試。精度損失來源於sqrt
操做;溢出是當座標接近\(10^5\)時,\(\Delta=r^2{d_r}^2-D^2\)等判據可能超過long long
的表示範圍,所以圓相關一切計算改用double
進行。
測試樣例徹底覆蓋了核心計算代碼:
在博客中詳細介紹每種異常的設計目標。每種異常都要選擇一個單元測試樣例發佈在博客中,並指明錯誤對應的場景。(5')
異常類型 | 設計目標 | 樣例 |
---|---|---|
CMDFormatException | 命令行輸入錯誤 | ./intersect.exe -p xx |
FileNotFoundException | 輸入文件不存在 | ./intersect.exe -i nowhere -o out.txt |
FileFromatException | 文件內容格式錯誤 | C L 1 1 -1 |
CoordinateLimitExceedException | 座標超限 | 1 C 999999 0 1 |
LineDefinitionException | 兩個參數點重合 | 1 L 1 1 1 1 |
CircleDefinitionException | 圓的半徑小於等於零 | 1 C 0 0 -1 |
InfinateIntersectionException | 幾何對象間存在重疊 | 2 R 0 1 0 2 S 0 3 0 4 |
由於以前沒有GUI編程的經驗, 在設計界面模塊以前,我首先調查了windows下有哪些GUI開發的庫可使用。
1.MFC
2.QT
3.WPF
4.WTL
在調查以後, 據網上評價QT比較好用, 並且是跨平臺的, 可是由於安裝文件過大, 電腦給windows的分區不足, 最終選擇了VS自帶的MFC。
MFC有兩種設計方式, 一個是dialog app一個是document app, 我選擇的是dialog app, 開發一個窗口。
使用visual studio mfc生成dialog app後, 在資源文件裏能夠找到界面對應的文件, 打開後以下圖, 能夠添加組件
我主要使用了三種組件
Button組件用來獲取用戶的點擊操做, 每次點擊會觸發一個onclick函數
void CMFCApplication1Dlg::OnBnClickedButton1() { CString geomLine; edit_geo_obj.GetWindowTextW(geomLine); CT2CA sa(geomLine); std::string s(sa); addGeometryObject(s); }
函數內能夠添加各類操做, 好比在個人界面中, 有如下幾個按鈕
輸入文件
增長几何對象
刪除幾何對象
計算交點(而且繪製)
關閉
static text組件用來展現文字
Edit control是一個文本框, 能夠用來輸入文字, 每一個文本框會有一個變量, 用來獲取文字。
好比file.GetWindowTextW(geomline)
就是把文件輸入框中的文字讀入到geomLine這個Ctring中
最後, 點擊計算交點後, 會把從計算模塊獲得的交點繪製出來, 調用draw函數畫在GUI的中央, 以下圖所歐式
因爲咱們的接口比較少, 在界面模塊對接時很流暢。
獲得intersectProjectDll.lib和Interface.h後, 我看到有三個接口
__declspec(dllexport) void readFile(string); __declspec(dllexport) void addGeometryObject(string); __declspec(dllexport) void removeGeometryObject(string); __declspec(dllexport) pair<vector<string>, vector<Point>> getResult();
這三個接口是咱們以前商定好的接口, 儘可能隱藏內部實現細節, 只暴露三個接口
功能以下圖
圖中有三個按鈕, 輸入文件調用readFile
, 添加幾何對象調用addGeometryObject
, 計算交點調用getResult
而且繪製
實現以上功能後, 對接工做完成。
使用工具: 騰訊會議
具體過程:
結對編程的優勢:
結對編程的缺點:
在結對編程的時候, 每個人的優缺點以下:
對駕駛員的優勢
對駕駛員的缺點
對領航員的優勢
對領航員的缺點
咱們互換的組是 http://www.javashuo.com/article/p-dumtxcfu-nn.html
咱們選擇的組和咱們有類似的接口, 在替換核心模塊的時候經歷了一下幾個步驟:
1.修改dll, lib路徑, 成功引入頭文件, 可以連接到庫
2.修改輸入文件, 添加幾何對象, 計算交點的接口名稱
3.運行
運行結果以下: