这篇博客是软件工程基础(罗杰、任建)的第三次课程做业(我的项目做业)git
项目 | 内容 |
---|---|
这个做业属于哪一个课程 | 软件工程基础(罗杰,任建) |
这个做业的要求在哪里 | 做业要求的连接 |
我在这个课程的目标是 | 提高对软件工程的宏观和微观的全面认识,并加以实践 |
做业在哪些方面帮我实现目标 | 亲身实践我的项目开发的完整流程 |
个人教学班级 | 006 |
个人GitHub项目地址 | https://github.com/SnowOnVolcano/IntersectProject.git |
在开始实现程序以前,在下述 PSP 表格记录下你估计将在程序的各个模块的开发上耗费的时间。(0.5')github
在你实现完程序以后,在下述 PSP 表格记录下你在程序的各个模块上实际花费的时间。(0.5')算法
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 15 | 20 |
· Estimate | · 估计这个任务须要多少时间 | 15 | 20 |
Development | 开发 | 330 | 470 |
· Analysis | · 需求分析 (包括学习新技术) | 60 | 80 |
· Design Spec | · 生成设计文档 | 30 | 20 |
· Design Review | · 设计复审 (和同事审核设计文档) | 0 | 0 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 10 | 10 |
· Design | · 具体设计 | 40 | 60 |
· Coding | · 具体编码 | 100 | 120 |
· Test | · 测试(自我测试,修改代码,提交修改 | 90 | 180 |
Reporting | 报告 | 75 | 110 |
· Test Report | · 测试报告 | 45 | 60 |
· Size Measurement | · 计算工做量 | 10 | 10 |
· Postmortem & Process Improvement Plan | · 过后总结, 并提出过程改进计划 | 20 | 40 |
Total | 合计 | 420 | 600 |
解题思路描述。即刚开始拿到题目后,如何思考,如何找资料的过程。(3')函数
读完问题的第一思路,是利用高中学到的 通常方程法 进行交点的求解:工具
这样的解法有几个好处:性能
D
是否为 0,直接判断两直线是否平行;set
用来存放已获得的交点,直接在存入时进行除重,最终结果输出 set
的大小便可;固然,其缺点也很明显:单元测试
N
条直线的样本,须要进行 \(C_N^2\) 次计算,时间复杂度为 \(O(n^2)\);set<(x,y)>
进行的方式进行存储,则须要进行浮点运算,这既会带来精度的损失,也会加长运行时间。若是不采用直接计算的方法,如何得出交点个数呢?我想到的另外一个方法是,作减法。学习
若是任意的两条直线都相交且任意的三条直线不交于同一点,那么对于具备 N
条直线的样本,交点的个数为 \(C_N^2\),对通常状况就有,测试
可是,仔细想一想,这种方法彷佛并不比思路简单,由于我没有想到好的算法去计算同一交点的直线数目……优化
思路三
想不到好的算法,我最后只能决定使用直接计算的方法,可是我想其实思路一的方法还能够简单地优化一下细节,减少精度损失,有两个方法,
set
的排序函数进行重载,设置必定的精度范围,这样能够必定程度地减少精度损失,可是没法从根本上避免。我最终选择了后者,以平衡精度和时间复杂度。
设计实现过程。设计包括代码如何组织,好比会有几个类,几个函数,他们之间关系如何,关键函数是否须要画出流程图?单元测试是怎么设计的?(4')
Point
:表示点 \((x,y)\),其中 Point.x
、Point.y
分别表示点的纵横坐标;Line
:表示直线 \(ax+by+c=0\),其中 Line.a
、Line.b
、Line.c
分别对应直线的三个参数;Point
和 Line
的构造函数,计算两直线交点的函数 calLineLineIst(...)
,主函数;
各函数关系以下,
我主要进行了三个方面的单元测试:
如下是个人一些单元测试的测试点的图形示意:
记录在改进程序性能上所花费的时间,描述你改进的思路,并展现一张性能分析图(由 VS 2019 的性能分析工具自动生成),并展现你程序中消耗最大的函数。(3')
代码说明。展现出项目关键代码,并解释思路与注释说明。(3')
// calculate the intersections of two lines static void calLineLineIst(Line& line1, Line& line2) { int D; D = line1.a * line2.b - line2.a * line1.b; switch (D) { case 0: // parallel break; default: // line1: a1*x+b1*x+c1=0, line2: a2*x+b2*x+c2=0 // ==> x=(b1*c2-b2*c1)/(a1*b2-a2*b1), // y=(a2*c1-a1*c2)/(a1*b2-a2*b1) // let D=a1*b2-a2*b1 // ==> x=(b1*c2-b2*c1)/D, y=(a2*c1-a1*c2)/D Point point = { (line1.b * line2.c - line2.b * line1.c) / (float)D, (line2.a * line1.c - line1.a * line2.c) / (float)D }; points.insert(point); break; } }
集合的排序和精度的肯定
bool operator == (const Point& other) const { return fabs(x - other.x) < 0.00000001 && fabs(y - other.y) < 0.00000001; } bool operator < (const Point& other) const { if (x != other.x) { return x < other.x; } else { return y < other.y; } }
// calculate the intersections of line and Circle static void calLineCircleIst(Line& line, Circle& circle) { int intercept; // intercept=r^2-d^2=r^2-(ax+by+c)^2/(a^2+b^2) intercept = (int)(pow(circle.r, 2) - pow(line.a * circle.x + line.b * circle.y + line.c, 2) / (pow(line.a, 2) + pow(line.b, 2))); // not intersect if (intercept < 0) { return; } // tLine is perpendicular to line Line tLine = { line.b, -line.a, line.a * circle.y - line.b * circle.x }; int D; D = tLine.a * line.b - line.a * tLine.b; // tPoint is the intersection of line and tLine Point tPoint = { (tLine.b * line.c - line.b * tLine.c) / (float)D, (line.a * tLine.c - tLine.a* + line.c) / (float)D }; switch (intercept) { case 0: // line is tangent to circle points.insert(tPoint); break; default:// line passes through circle float vecX; float vecY; float offset; // (vecX, vecY) is a unit vector vecX = (float)(line.b / sqrt(pow(line.a, 2) + pow(line.b, 2))); vecY = (float)(-line.a / sqrt(pow(line.a, 2) + pow(line.b, 2))); // Offset is half of the intercept offset = (float)sqrt(intercept / (pow(line.a, 2) + pow(line.b, 2))); // intersection = tPoint +/- vec*offset Point ist1 = { tPoint.x + vecX * offset, tPoint.y + vecY * offset }; Point ist2 = { tPoint.x - vecX * offset, tPoint.y - vecY * offset }; points.insert(ist1); points.insert(ist2); break; } }
// calculate intersections of two circles static void calCircleCircleIst(Circle& circle1, Circle& circle2) { int radiusSum; int radiusDiff; int centerDis; radiusSum = (int)pow(circle1.r + circle2.r, 2); radiusDiff = (int)pow(circle1.r - circle2.r, 2); centerDis = (int)(pow(circle1.x - circle2.x, 2) + pow(circle1.y - circle2.y, 2)); // not intersect if (centerDis > radiusSum || centerDis < radiusDiff) { return; } // line passes both two intersections of circles Line line = { circle1.d - circle2.d, circle1.e - circle2.e, circle1.f - circle2.f }; // the intersections of two circles are also the intersections of line and circle calLineCircleIst(line, circle1); }