2020BUAA软工个人项目作业

17373010 杜博玮
项目 内容
这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健)
这个作业的要求在哪里 个人项目作业
我在这个课程的目标是 学习软件工程,培养工程开发能力、团队协作能力,开阔视野
这个作业在哪个具体方面帮助我实现目标 通过个人尝试对软件工程构建一定认识

教学班级 005

项目地址 https://github.com/Cuogeihong/IntersectProject

PSP表格:

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划
Estimate 估计这个任务需要多少时间 15 10
Development 开发
Analysis 需求分析 (包括学习新技术) 80 90
Design Spec 生成设计文档 45 40
Design Review 设计复审 15 10
Coding Standard 代码规范 (为目前的开发制定合适的规范) 15 10
Design 具体设计 60 75
Coding 具体编码 240 200
Code Review 代码复审 15 20
Test 测试(自我测试,修改代码,提交修改) 120 150
Reporting 报告
Test Reporting 测试报告 45 40
Size Measurement 计算工作量 15 10
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 15 20
合计 680 675

解题思路:

我的思路主要是暴力求解。通过处理输入数据,将直线表示为\(ax+by+c=0\)的形式,将圆表示为\((x-a)^2+(y-b)^2=r^2\)的形式,使用vector数组储存。计算时分为三种情况,直线与直线之间,圆与直线之间,圆与圆之间,对这三种情况分别利用已经推导好的公式计算得出结果,将结果去重后得到答案。

通过数学知识我分析了暴力求交点的方法。

计算两直线之间的交点时先判断是否平行,之后直接代入两个二元一次方程联立后的解即可得到结果。

计算直线与圆之间的交点时首先判断直线是否垂直于x轴,如果是,则直接求出\(x\),此后解一元二次方程得到\(y\)。否则通过直线将\(y\)从圆的方程组消掉,求解一元二次方程得到\(x\),再代回直线求得\(y\)。

计算圆与圆之间交点直接将两圆相减得到直线方程,之后按照计算直线与圆之间的交点的方法求出圆与圆之间交点。此时需注意直线的\(a\)与\(b\)均为0的情况。

在后来优化代码时我发现了使用向量法求交点的方法,但是程序已经比较完善了,使用向量法需要几乎重写程序,因此我没有采用向量法。

设计实现过程:

主要功能在Image类中实现。main函数主要处理命令行参数以及接受输入并传给Image类。

Image类中主要有6个函数,其中addLine函数和addCircle函数处理输入数据并存储,getNum函数接受main函数调用并总领计算,getLineAndLinePoint,getLineAndCirclePoint,getCircleAndCirclePoint三个函数分别计算两直线之间的交点、直线与圆之间的交点、圆与圆之间交点。

此外程序定义了line、circle、point数据类型方便程序编写。

整体而言程序实现并不复杂。

单元测试主要测试以下功能。

  • 两直线相交

  • 两直线平行

  • 三条直线相交于同一点

  • 三条直线其中两直线平行

  • 直线与圆相交

  • 直线与圆相切

  • 直线与圆相离

  • 圆与圆外切

  • 圆与圆相交

  • 圆与圆外离

  • 圆与圆内切

  • 圆与圆内含

    		TEST_METHOD(TestMethod1)
    {
    // TODO: 在此输入测试代码
    Image *img = new Image();
    img->addLine(0, 0, 1, 1);
    img->addLine(1, -1, 0, 0);
    Assert::AreEqual(img->getNum(), 1);
    }
    TEST_METHOD(TestMethod2)
    {
    // TODO: 在此输入测试代码
    Image *img = new Image();
    img->addLine(0, 0, 1, 1);
    img->addLine(3, 4, 4, 5);
    Assert::AreEqual(img->getNum(), 0);
    }
    TEST_METHOD(TestMethod3)
    {
    // TODO: 在此输入测试代码
    Image *img = new Image();
    img->addLine(0, 0, 1, 1);
    img->addLine(-1, 1, 1, -1);
    img->addLine(3, 4, -3, -4);
    Assert::AreEqual(img->getNum(), 1);
    }
    TEST_METHOD(TestMethod4)
    {
    // TODO: 在此输入测试代码
    Image *img = new Image();
    img->addLine(0, 0, 1, 1);
    img->addLine(-1, 1, 1, -1);
    img->addLine(3, 4, -4, -3);
    Assert::AreEqual(img->getNum(), 2);
    }
    TEST_METHOD(TestMethod5)
    {
    // TODO: 在此输入测试代码
    Image *img = new Image();
    img->addCircle(0, 0, 1);
    img->addLine(0, 0, 1, 1);
    Assert::AreEqual(img->getNum(), 2);
    }
    TEST_METHOD(TestMethod6)
    {
    // TODO: 在此输入测试代码
    Image *img = new Image();
    img->addCircle(0, 0, 1);
    img->addLine(0, 1, 1, 1);
    Assert::AreEqual(img->getNum(), 1);
    }
    TEST_METHOD(TestMethod7)
    {
    // TODO: 在此输入测试代码
    Image *img = new Image();
    img->addCircle(0, 0, 1);
    img->addLine(2, 2, 2, 0);
    Assert::AreEqual(img->getNum(), 0);
    }
    TEST_METHOD(TestMethod8)
    {
    // TODO: 在此输入测试代码
    Image *img = new Image();
    img->addCircle(0, 0, 1);
    img->addCircle(2, 0, 1);
    Assert::AreEqual(img->getNum(), 1);
    }
    TEST_METHOD(TestMethod9)
    {
    // TODO: 在此输入测试代码
    Image *img = new Image();
    img->addCircle(0, 0, 1);
    img->addCircle(1, 0, 1);
    Assert::AreEqual(img->getNum(), 2);
    }
    TEST_METHOD(TestMethod10)
    {
    // TODO: 在此输入测试代码
    Image *img = new Image();
    img->addCircle(0, 0, 1);
    img->addCircle(3, 0, 1);
    cout << img->getNum() << endl;
    Assert::AreEqual(img->getNum(), 0);
    }
    TEST_METHOD(TestMethod11)
    {
    // TODO: 在此输入测试代码
    Image *img = new Image();
    img->addCircle(0, 0, 4);
    img->addCircle(3, 0, 1);
    cout << img->getNum() << endl;
    Assert::AreEqual(img->getNum(), 1);
    }
    TEST_METHOD(TestMethod12)
    {
    // TODO: 在此输入测试代码
    Image *img = new Image();
    img->addCircle(0, 0, 4);
    img->addCircle(0, 1, 1);
    cout << img->getNum() << endl;
    Assert::AreEqual(img->getNum(), 0);
    }

    单元测试运行结果:

性能分析与优化:

此前我采用set进行去重工作,通过性能分析我们可以看到,set花费了超过80%的CPU时间,因此需要对set进行优化。这样我找到了unordered_set,它利用hash来实现set的功能,不会对集合内数据进行排序,在修改后性能得到了大幅度的提高。

代码说明:

求两直线交点

for (int i = 0; i < linesLength; i++) {
for (int j = i + 1; j < linesLength; j++) {//避免重复运算
line lineA, lineB;
lineA = lines[i];
lineB = lines[j];
double judgeNum = lineA.a * lineB.b - lineA.b * lineB.a;//判断两直线是否平行
if (fabs(judgeNum) < 1e-8) {//防止因为浮点数以无限逼近于0代表0
continue;
}
double x, y;
x = (lineB.c * lineA.b - lineA.c * lineB.b) / judgeNum;//计算交点x
y = (lineB.a * lineA.c - lineA.a * lineB.c) / judgeNum;//计算交点y
point cur(x, y);
points.insert(cur);//将交点放入集合中去重
}
}

求直线与圆交点

for (int i = 0; i < linesLength; i++) {
for (int j = 0; j < circlesLength; j++) {
line curLine;
circle curCircle;
curLine = lines[i];
curCircle = circles[j];
if (curLine.b == 0) {//当直线垂直于x轴时
double distanceLC = curLine.c / curLine.a + curCircle.x;
if (fabs(fabs(distanceLC) - abs(curCircle.r)) < 1e-8) {
point cur(-1 * curLine.c / curLine.a, curCircle.y);
points.insert(cur);//将交点放入集合中去重
}
else if (fabs(distanceLC) - abs(curCircle.r) < 0) {
double sqrtTmp = sqrt(curCircle.r * curCircle.r -
distanceLC * distanceLC);
point cur1(-1 * curLine.c / curLine.a, curCircle.y + sqrtTmp);
point cur2(-1 * curLine.c / curLine.a, curCircle.y + sqrtTmp);
points.insert(cur1);//将交点放入集合中去重
points.insert(cur2);//将交点放入集合中去重
}
}
else {
//用x表示y的值 y=kx+b
double k = -1 * curLine.a / curLine.b, b = -1 * curLine.c / curLine.b;
double equationA, equationB, equationC;//表示化简得到的一元二次方程
equationA = k * k + 1;
equationB = 2 * (k * b - k * curCircle.y - curCircle.x);
equationC = curCircle.x * curCircle.x - curCircle.r * curCircle.r +
(b - curCircle.y) * (b - curCircle.y);
double judge = equationB * equationB - 4 * equationA * equationC;//判别式
if (fabs(judge) < 1e-8) {
//一元二次方程只有一个根时
double answerX = -1 * equationB / 2 / equationA;
point cur(answerX, answerX * k + b);
points.insert(cur);//将交点放入集合中去重
}
else if (judge > 0) {
//计算x的两个根并推出y的值
double answerX1 = (-1 * equationB + sqrt(judge)) / 2 / equationA;
point cur1(answerX1, answerX1 * k + b);
points.insert(cur1);//将交点放入集合中去重
double answerX2 = (-1 * equationB - sqrt(judge)) / 2 / equationA;
point cur2(answerX2, answerX2 * k + b);
points.insert(cur2);//将交点放入集合中去重
}
}
}
}

两圆之间交点的计算与直线与圆计算相同,不再放出。

消除 Code Quality Analysis 中的所有警告:

2020BUAA软工个人项目作业的更多相关文章

  1. 2020BUAA软工结伴项目作业

    2020BUAA软工结伴项目作业 17373010 杜博玮 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 结伴项目作业 我在这个课程的目标是 学 ...

  2. 【BUAA 软工个人项目作业】玩转平面几何

    BUAA 软件工程个人项目作业 项目 内容 课程:2020春季软件工程课程博客作业(罗杰,任健) 博客园班级链接 作业:BUAA软件工程个人项目作业 作业要求 课程目标 学习大规模软件开发的技巧与方法 ...

  3. BUAA 软工 结对项目作业

    1.相关信息 Q A 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 结对项目作业 我在这个课程的目标是 系统地学习软件工程开发知识,掌握相关流程和技术,提升 ...

  4. BUAA软工-结对项目作业

    结对项目作业 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 结对项目作业 我在这个课程的目标是 通过这门课锻炼软件开发能力和经验,强化与他人合作 ...

  5. python简单实现论文查重(软工第一次项目作业)

    前言 软件工程 https://edu.cnblogs.com/campus/gdgy/informationsecurity1812 作业要求 https://edu.cnblogs.com/cam ...

  6. 2020BUAA软工提问回顾和个人总结作业

    2020BUAA软工提问回顾和个人总结作业 17373010 杜博玮 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 提问回顾和个人总结作业 我在 ...

  7. 2020BUAA软工个人博客作业-软件案例分析

    2020BUAA软工个人博客作业-软件案例分析 17373010 杜博玮 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 个人博客作业-软件案例分 ...

  8. 2020BUAA软工个人博客作业

    2020BUAA软工个人博客作业 17373010 杜博玮 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 个人博客作业 我在这个课程的目标是 学 ...

  9. 2020BUAA软工热身作业

    2020BUAA软工热身作业 17373010 杜博玮 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 热身作业 我在这个课程的目标是 学习软件工 ...

随机推荐

  1. Spring AOP Aspect的简单实现(基于注解)

    第1步:声明使用注解 <!-- 配置扫描注解--> 扫描包的位置<context:component-scan base-package="com.zz"/> ...

  2. Java字符串常量池及字符串判等解析

    一.理解"=="的含义 "=="常用于两个对象的判等操作,在Java中,"=="主要有以下两种用法: 1.基础数据类型:比较的是他们的值是否 ...

  3. Jenkins教程(七)实现 GitLab 提交/合并代码触发构建

    楔子 最近公司推行统一构建平台(基于 Jenkins + Kubernetes 插件创建 slave),原来部门自建的 Jenkins 不让用了. 迁移上统一构建平台的最大阻力是前端模块发布的问题: ...

  4. 洛谷P1088——火星人(全排列+数学模拟)

    题目描述 人类终于登上了火星的土地并且见到了神秘的火星人.人类和火星人都无法理解对方的语言,但是我们的科学家发明了一种用数字交流的方法.这种交流方法是这样的,首先,火星人把一个非常大的数字告诉人类科学 ...

  5. linux7可以通过远程和localhost访问mysql,但是127.0.0.1不能访问

    网上搜索的其他方法都试过,不行 比如设置权限,开放端口,配置数据库... 最好偶然一个搜索查看可能原因是防火墙端口问题: vim /etc/sysconfig/iptables 在文件中添加下面语句 ...

  6. Shell系列(13)- read

    前言 作用是往脚本中传递参数,之前文章的位置参数变量也有此功能,但是只适用于脚本的作者,为什么?第三方用户不知道这个脚本要传递哪些参数,这些参数分别是什么.本篇随笔read就可以实现上述功能,别且该命 ...

  7. 传说中 VUE 的“语法糖”到底是啥?

    一.什么是语法糖? 语法糖也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语.指的是计算机语言中添加的一种语法,在不影响功能的情况下,添加某种简单的语 ...

  8. LeetCode2-链表两数和

    目录 LeetCode2-链表两数和 题目描述 示例提示 经验教训 参考正解 题目描述 示例提示 经验教训 链表题的判空条件不是万能的,有时候示例会极其复杂,根本难以通过判空来区分不同情况. /** ...

  9. 由浅入深了解cookie

    什么是 Cookie "cookie 是存储于访问者的计算机中的变量.每当同一台计算机通过浏览器请求某个页面时,就会发送这个 cookie.你可以使用 JavaScript 来创建和取回 c ...

  10. P5437-[XR-2]约定【拉格朗日差值,数学期望】

    正题 题目链接:https://www.luogu.com.cn/problem/P5437 题目大意 \(n\)个点的完全图,连接\(i,j\)的边权值为\((i+j)^k\).随机选出一个生成树, ...