【BUAA_2020_软工】个人作业
个人项目作业博客
1. 在文章开头给出教学班级和可克隆的 Github 项目地址(例子如下)。(1')
项目 | 内容 |
---|---|
北航2020软工 | 班级博客 |
作业要求 | 具体要求 |
项目GitHub地址 | 个人项目 |
教学班级 | 005(周三上午三四节) |
2. 在开始实现程序之前,在下述 PSP 表格记录下你估计将在程序的各个模块的开发上耗费的时间。(0.5')
见Part 7.
3. 解题思路描述。即刚开始拿到题目后,如何思考,如何找资料的过程。(3')
首先读题后,发现:这个问题,一定程度上是一个数学问题,所以思路是按照数学来解题。
先不考虑附加题:
因为有重合点的情况,一组直线的所有交点,如果不计算并且存下来进行对比,最终的结果是无法保证的,所以先考虑两条直线的交点计算,再考虑存储结构。
直线与直线的交点求法有多种,方便电脑计算的有哪些? ------> 调研
方法一:
通过点\((x_1, y_1),\;\;(x_2, y_2)\)求得直线\(l1\)的斜率和截距\(k_1, \;b_1\),另一条直线同理
\[\left\{ \begin{array}{rcl}
l_1 : y = k_1*x + b_1\\
l_2 : y = k_2*x + b_2
\end{array}\right.
\] 联立求解得
\[\left\{ \begin{array}{rcl}
&x_0 = \frac{b_2-b_1}{k_1-k_2}&\\
&y_0 = k_1*x_0+b_1& \;\;(or\;y_0 =k_2*x_0+b_2)
\end{array}\right.
\]
方法二:选择√
两条直线:
\[\left\{ \begin{array}{rcl}
l_1 : a_1x+b_1y+c_1=0\\
l_2 : a_2x+b_2y+c_2=0
\end{array}\right.
\;\;\;\;\;\;\;\ \;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;(1)
\] 把每条直线的两个点带入解析中得:
\[\left\{ \begin{array} \\
a_1 = y_2 - y_1\\
b_1 = x_1 - x_2\\
c_1 = x_2y_1-x_1y_2
\end{array}\right.
\] 直线\(l_2\)类似,可以求得未知数\(a_2,b_2,c_2\);之后由(1)得:
\[D =
\left|\begin{array}{ccc}
a_1 & b_1\\
a_2 & b_2
\end{array}\right|
=a_1b_2-a_2b_1\quad\quad(D == 0 则平行否则有交点)\\
x_0 = (b_1c_2-b_2c_1)/D\\
y_0 = (a_2c_1-a_1c_2)/D
\] 这种方法的好处在于不用特判斜率不存在的情况,只需要根据D判断是否有交点进行计算即可。
这时考虑交点的存储结构(使用c++),每当算出一个新的交点时,都需要判断是否已经有这个点,选择三种存储结构
- set:不重复的元素集合,但是在insert的时候有大量的排序操作
- hashMap:通过hash值来存储,每次计算hash值来确定是否已经存在
- vector:无脑push_back,最后扫描去重
经过实测,最终的效果显示,第三种方式的效果更好,set和hashMap因为比较次数太频繁和计算hash值太频繁导致时间消耗很大,难以完成任务。(仅代表个人程序结果,不排除其他因素影响)
附加题的思路基于上述,考虑直线和圆,圆和圆的交点计算:
直线和圆:
首先判断直线和圆是否相交,通过计算圆心到直线的距离与半径比较
向量\(\overrightarrow{AB}\)与向量 \(\overrightarrow{AC}\) 的外积的模长代表以AB、AC为边的平行四边形的面积S,利用面积公式 \(S=|\overrightarrow{AB}|*d\),可以得到 \(d = S / |\overrightarrow{AB}|\);
若相交则计算交点坐标:
- 求垂足D的坐标:见上图,利用内积公式\(\overrightarrow{AB}·\overrightarrow{AC}=|\overrightarrow{AB}||\overrightarrow{AC}|cos\theta=|\overrightarrow{AB}|· AD\),所以可以得到AD的长度,则向量\(\overrightarrow{AD}=\frac{AD}{|\overrightarrow{AB}|}·\overrightarrow{AB}\),又因为知道了A点坐标,所以D点坐标就可以得到
- 根据向量\(\overrightarrow{AB}\)求得AB方向的单位向量\(\overrightarrow{e}\),然后,利用直角三角形算出GD的长度为base;
- 此时有了D点坐标,GD长度,和直线AB上的单位向量,可以得到G和H点的坐标:
- \(G = D - \overrightarrow{e} * base\)
- \(H = D + \overrightarrow{e} * base\)
圆和圆的交点求法有公式法,但是从一篇博客中找到了更好的解法,就是仿照上面按照公式计算,在此不赘述。博客地址
4. 设计实现过程。设计包括代码如何组织,比如会有几个类,几个函数,他们之间关系如何,关键函数是否需要画出流程图?单元测试是怎么设计的?(4')
基本要求:
- 类:
- Point:点,因为要判断是否是同一个点,需要实现判断函数
- Line:数据实体,保存输入文件中的信息,并且用于计算
- Circle:类似于Line(附加题需求)
- 函数:
- getCross():计算两条直线的交点,将结果直接保存在全局变量Result中,具体过程为第三部分的方法二
- getAllIntersec():把输入文件读取的Lines信息传入,计算所有的交点,简单的循环计算。
整体逻辑如下图:
可以看到,Line和Point其实并没有交集,所以这里的Line本质上可以直接删除,只需要记录对应的数据传入getAllIntersec函数即可,不过为了方便附加题的实现,这里没有那么做。
附加题:
- 计算交点分为三种情况:
- 直线与直线:见上图
- 直线与圆:循环遍历直线和每一个圆,调用函数求交点;
- 圆与圆:循环遍历圆和圆,调用函数求交点;
- 读取数据后,把直线存在lines中,圆存放在circles中,然后执行上面的三种计算,交点全部存放在全局结果Result中,最后读取Result的大小即为结果。
其中直线和圆求交点的代码按照Part 3的附加题思路,具体代码见Part 6.
圆和圆求交点的代码按照博客方法计算,具体思路见Part 6.
(注:因为是按照公式来计算,所以再次不进行详细的赘述,放到Part6)
单元测试:
主要对三个子函数进行测试:
- 直线和支线求交点
- 一条直线无斜率,一条有
- 一条直线平行于x轴,一条正常
- 一条直线无斜率,一条平行于x轴
- 两条直线都有斜率(包含了2,3)
- 直线和圆
- 相交(过圆心与不过圆心两种)
- 相切,一个交点
- 不相交
- 圆和圆
- 相交,外交;
- 相交,内交
- 相切,外切
- 相切,内切(内切又分为两种,c1内切c2,c2内切c1)
- 分离,外离
- 分离,内离
- 以及测试了一些小函数的功能,求外积和内积
最终的测试结果如下:
上面的测试时基本的功能测试,为了进一步测试,通过python生成随机数据来进行验证,和同学对拍来验证结果。
通过对拍,找出以下bug:
- 直线与圆相切计算,需要控制精度,否则会因为计算产生的误差导致判断失误
- 圆和圆的内切需要分两种情况
- 以及不同的精度控制范围导致结果的不同,最后测试出自己程序的稳定范围在\(1^{-11} \thicksim 1^{-10}\),这个精度对于直线和直线的计算,已经足够,因为数据范围位\((-100000, 100000)\),最多出现二次项,也就是\(1^{10}\)的级别,对应于精度\(1^{-10}\),而直线和圆,圆和圆的计算,引入的计算误差使得精度到了\(1^{-12}\)时程序结果就不稳定了。
代码分支覆盖率如下图:
5. 记录在改进程序性能上所花费的时间,描述你改进的思路,并展示一张性能分析图(由 VS 2019 的性能分析工具自动生成),并展示你程序中消耗最大的函数。(3')
从写完最初的版本到现在几乎一直处于改进状态,大概是10个小时吧,期间找了很多资料,也和同学谈论了很多。
思考能否不计算出交点坐标就能到最后的结果,目前找不到相关说明,自己也没有头绪;
改善固有程序:
- 一开始使用set来存计算出来的Point,这样好处是可以自动去重,问题是数据变大后set.insert()是一个占据很大热点的函数,耗时太多,超时;
- 考虑hashmap,但是一个同学使用的hashmap,他的程序效果同样很慢,自己初步尝试后放弃;
- 既然这样,干脆选择最简单的vector,最后进行去重,一开始无脑push_back计算出来的交点,最后操作一次,因为满足交点个数小于MAX=5000000,只要在超过MAX时就去重,这样最后在去重一次,就不会出现无脑push的导致重复点过多的问题。
包装vector.push_back()函数,添加后,若超过MAX,就排序去重,然后添加,最后全部计算完成后,再次排序去重,得到结果。性能截图如下,主要的热点就是排序去重的部分,占据76%左右,而set占据80%左右,好处是vector操作较为轻量级。总体时间节省不少。
- 热点函数展示
6. 代码说明。展示出项目关键代码,并解释思路与注释说明。(3')
直线和直线求交点:
采用前述的方法二计算,按照公式逻辑计算即可,只需要特判两直线是否平行即可。
//l1: a1*x + b1*y + c1 = 0
//l2: a2*x + b2*y + c2 = 0
//向量法求解:
//D判断是否平行
//x0 = (b1 * c2 - b2 * c1) / D
//y0 = (a2 * c1 - a1 * c2) / D
bool getCross(Line l1, Line l2, Point* res)
{
//求l1的a1,b1,c1
double a1 = l1.getPy() - l1.getQy();
double b1 = l1.getQx() - l1.getPx();
double c1 = l1.getPx() * l1.getQy() - l1.getQx() * l1.getPy();
//求l2的a2,b2,c2
double a2 = l2.getPy() - l2.getQy();
double b2 = l2.getQx() - l2.getPx();
double c2 = l2.getPx() * l2.getQy() - l2.getQx() * l2.getPy(); double D = a1 * b2 - a2 * b1;
//平行则退出,没有交点
if (D == 0) {
return false;
}
res->setPoint((b1 * c2 - b2 * c1) / D, (a2 * c1 - a1 * c2) / D);
return true;
}
直线和圆求交点:
- 先判断是否有交点
- 然后利用向量法求解
bool getCircleLineCross(Circle c, Line l)
{
Point ceter = c.getCeter();
double R = c.getR();
//求圆心到直线的距离
double juli = getDistance(l, ceter);
//判断是否相交,或者相切,还是不相交
if (juli > R + PRECISION) {
return false;
} //求垂足的坐标
Vector segment = l.getQ() - l.getP();
double ratio = dot(ceter - l.getP(), segment) / segment.norm();
Point foot = l.getP() + segment * ratio; //特判,如果相切,则交点就是垂足坐标
if (abs(juli - R) < PRECISION) {
addPoint(foot);
return true;
} //直线AB的单位向量,与AB同向
Vector e = segment / segment.module();
//base = 直线与圆相交的弦的一半. 利用勾股定理
double base = sqrt(R * R - (ceter - foot).norm());
//向量加减得到两个点的坐标
Point p1 = foot - e * base;
Point p2 = foot + e * base;
addPoint(p1);
addPoint(p2);
return true;
}
圆和圆求交点:
按照公式步骤求解,具体逻辑就是计算公式,不赘述。
bool getCircleCross(Point c1, double r1, Point c2, double r2)
{
double x1 = sqrt((c1 - c2).norm());
double b1 = abs(r1 - r2);
double b2 = abs(r1 + r2);
//判断相离,内离和外离
if (x1 < b1 || x1 > b2) {
return false;
}
//外切
else if (x1 == b2) {
Vector e = (c2 - c1) / (c2 - c1).module();
addPoint(c1 + e * r1);
return true;
}
//内切
else if (x1 == b1) {
Vector e = (c2 - c1) / (c2 - c1).module();
if (r1 < r2) {
addPoint(c1 - e * r1);
}
else {
addPoint(c1 + e * r1);
}
}
//相交
else {
Vector AB = (c2 - c1);
double l = AB.module();
Vector e = AB / l;
double AE = (r1 * r1 - r2 * r2 + l * l) / (2 * l);
Point E = c1 + AB * AE / l;
double CE = sqrt(r1 * r1 - AE * AE);
//两圆心横坐标相同
if (c1.getX() == c2.getX()) {
Point left(E.getX() - CE, E.getY());
Point right(E.getX() + CE, E.getY());
addPoint(left);
addPoint(right);
}
//两个圆心纵坐标相同
else if (c1.getY() == c2.getY()) {
Point up(E.getX(), E.getY() - CE);
Point down(E.getX(), E.getY() + CE);
addPoint(up);
addPoint(down);
}
//一般情况
else {
double k1 = (c2.getY() - c1.getY()) / (c2.getX() - c1.getX());
double k2 = -1 / k1;
double EF = sqrt(CE * CE / (1 + k2 * k2));
double cx = E.getX() - EF;
double cy = E.getY() + k2 * (cx - E.getX());
double dx = E.getX() + EF;
double dy = E.getY() + k2 * (dx - E.getX());
Point tmp(cx, cy);
addPoint(tmp);
tmp.setPoint(dx, dy);
addPoint(tmp);
}
}
return true;
}
7. 在你实现完程序之后,在下述 PSP 表格记录下你在程序的各个模块上实际花费的时间。(0.5')
PSP2.1 | Personal Software Process Stage | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | 60 |
· Estimate | · 估计这个任务需要的时间 | ||
Development | 开发 | 480 | 720 |
· Analysis | · 需求分析 | 30 | 60 |
· Design Spec | · 生成设计文档 | 30 | 30 |
· Design Review | · 设计复审 | 30 | 15 |
· Coding Standard | · 代码规范 | 30 | 15 |
· Design | · 具体设计 | 60 | 60 |
· Coding | · 具体编码 | 120 | 180 |
· Code Review | · 代码复审 | 60 | 240 |
· Test | · 测试 | 120 | 120 |
Reporting | 报告 | 60 | 120 |
· Test Report | · 测试报告 | 30 | 60 |
· Size Measurement | · 计算工作量 | 15 | 30 |
· Postmorten & Process Improvement Plan | · 事后总结,并提出过程改进计算 | 15 | 30 |
合计 | 600 | 900+ |
附录
Code Quality Analysis
【BUAA_2020_软工】个人作业的更多相关文章
- 软工团队作业--Scrum冲刺集合贴
软工团队作业--Scrum冲刺集合贴 团队 团队名称:广东靓仔六强选手 团队成员: 黄清山 黄梓浩 钟俊豪 周立 邓富荣 郑焕 博客链接 Scrum 冲刺 第一篇 Scrum 冲刺 第二篇 Scrum ...
- 2021软工-调研作业-Notion
2021软工-调研作业-Notion 项目 内容 这个作业属于哪个课程 2021春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 案例分析作业要求 我在这个课程的目标是 学习软件开发的工业化 ...
- 2020BUAA软工热身作业
2020BUAA软工热身作业 17373010 杜博玮 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 热身作业 我在这个课程的目标是 学习软件工 ...
- 软工个人作业4——Alpha阶段个人总结
一.个人总结 1.在alpha 结束之后, 每位同学写一篇个人博客, 总结自己的alpha 过程: 经过本次alpha阶段的冲刺,首先学到了很多,收获了很多,同时也蛮辛苦的.其实我觉得作为组员我有很认 ...
- 2020BUAA 软工-结对作业
结对作业 项目 内容 北航2020软工 班级博客 作业要求 具体要求 1.在文章开头给出教学班级和可克隆的 GitHub 项目地址(例子如下).(1') 教学班级 005 项目地址 GitHub 2. ...
- Fzu软工第一次作业-准备篇
(0)一些想说的话 我叫陈浩,是16级计算机一个很普通的学生.我是补选选软工实践这门课的.选软工实践这门课我想了很久.因为学长学姐告诉我这是一门很锻炼人又很辛苦的课程,需要大量的时间和精力.然而如今的 ...
- BUAA软工第一次作业-热身
第一次作业-热身 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) (北京航空航天大学 - 计算机学院) 这个作业的要求在哪里 第一次作业-热身作业(阅读) 我在这个课程 ...
- 停下来,回头看 ——记2020BUAA软工第一次作业-热身!
description: 'Mar 1st, 2020 - Mar 3rd, 2020' 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任建) 这个作业的要求在哪里 第一次作 ...
- 2018软工实践作业八之UML设计
1. 团队信息 队名:小白吃队 成员: 后敬甲 031602409 卢泽明 031602328 蔡文斌 031602301 葛亮 031602617 刘浩 031602423 黄泽 031602317 ...
随机推荐
- c++ 反汇编 继承
单继承,父类中没有虚函数 单继承,父类存在虚函数,子类重写虚函数 单继承,父类存在虚函数,子类不新定义虚函数 单继承,父类存在虚函数,子类新定义虚函数 单继承,父类不存在虚函数,子类定义虚函数 多继承 ...
- Android Studio中Switch控件有关 textOn 和 textOff 用法
•属性 textOn:控件打开时显示的文字 textOff:控件关闭时显示的文字 showText:设置是否显示开关上的文字(API 21及以上) •用法 <?xml version=" ...
- 第14 章 : Kubernetes Service讲解
Kubernetes Service 本文将主要分享以下四方面的内容: 为什么需要 K8s service: K8s service 用例解读: K8s service 操作演示: K8s servi ...
- Rancher 安装和使用-实践
Rancher 安装和使用 Rancher是一个完整的,开源的平台,用于在生产环境中部署和管理容器.它包括Kubernetes,Mesos和Docker Swarm的商业支持发行版,使得在任何基础架构 ...
- Ansible 教程
[注]本文译自:https://www.edureka.co/blog/ansible-tutorial/ 在阅读本文之前,你应该已经知道,Ansible 构成了 DevOps 认证的关键部分,它 ...
- (二)基于商品属性的相似商品推荐算法——Flink SQL实时计算实现商品的隐式评分
系列随笔: (总览)基于商品属性的相似商品推荐算法 (一)基于商品属性的相似商品推荐算法--整体框架及处理流程 (二)基于商品属性的相似商品推荐算法--Flink SQL实时计算实现商品的隐式评分 ( ...
- matlab结构体、数组和单元数组类型的创建
matlab结构体.数组和单元数组类型的创建 @ 目录 matlab结构体.数组和单元数组类型的创建 matlab结构体类型 数组类型 单元数组类型 matlab结构体类型 通过字段赋值创建结构体 创 ...
- Day13_67_interrupt() 方法
interrupt() 方法 中断线程 * interrupt()方法的简单理解 - interrupt() 方法只是改变线程的阻塞状态而已,让一个正在阻塞状态的线程,恢复执行.但是它不会中断一个正在 ...
- Manachar's Algorithm
1.模板 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAX=21000020; 4 char s[MAX], ...
- 浅谈Java的反射机制和作用
浅谈Java的反射机制和作用 作者:Java大师 欢迎转载,转载请注明出处 很多刚学Java反射的同学可能对反射技术一头雾水,为什么要学习反射,学习反射有什么作用,不用反射,通过new也能创建用户对象 ...