个人项目博客
项目 | 内容 |
---|---|
这个作业属于哪个课程 | 2020计算机学院软件工程(罗杰 任健) |
这个作业的要求在哪里 | 个人项目作业 |
教学班级 | 006 |
项目地址 | https://github.com/CrapbagMo/IntersectionPoints.git |
1. PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
Planning | 计划 | ||
· Estimate | · 估计这个任务需要多少时间 | 5 | 5 |
Development | 开发 | ||
· Analysis | · 需求分析 (包括学习新技术) | 60 | 90 |
· Design Spec | · 生成设计文档 | 10 | 2 |
· Design Review | · 设计复审 (和同事审核设计文档) | 10 | 3 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 10 | 5 |
· Design | · 具体设计 | 30 | 15 |
· Coding | · 具体编码 | 180 | 270 |
· Code Review | · 代码复审 | 30 | 20 |
· Test | · 测试(自我测试,修改代码,提交修改) | 240 | 120 |
Reporting | 报告 | ||
· Test Report | · 测试报告 | 60 | 30 |
· Size Measurement | · 计算工作量 | 10 | 10 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 10 | 10 |
合计 | 625 | 580 |
2. 解题思路描述
-
对于基础需求:
两直线相交,可直接将两直线表示为标准方程形式,交点由标准方程中的 A、B 可得。
对于第三条及之后的直线,与其他每一条直线求交点,然后放入维护的 unordered_map 里(用之前重写hash)保证点不重。最终的 size 就是答案。
时间复杂度是 \(O(n^2)\) ,不是很理想,但想不出其他算法。可以在读取直线时,将直线的斜率和直线存为 pair,对 斜率相等 的线进行剪枝,即先判断是否平行,若平行则无交点。可以减少一点计算。
-
对于附加题:
圆与直线的交点,先判断圆心到直线的距离,看是否有焦点。如果有交点,按照参考 中的方法,做垂线,求出弦的长度,然后在垂足的基础上加减向量。
圆与圆的交点可以转化为圆与直线的交点。
参考:https://blog.csdn.net/zhouzi2018/article/details/80550177
3. 设计实现过程
-
代码组织
- main.cpp
- 从输入文件里读取图形,调用相应的图形类中的方法求交点,输出结果
- 维护交点、直线容器
- shapes.h
- 图形类 class line (直线)
- generate_line : 定义直线的参数
- getDistance : 获取直线外一点到这条直线的距离
- getSlope : 获取一条直线的斜率
- getIntersectWithLine : 计算与另一条直线的交点并存入交点容器
- 图形类 class circle (圆)
- generate_circle : 定义圆的参数
- getIntersectWithLine : 计算与一条直线的交点
- getIntersectWithCircle : 计算与另一个圆的交点
- 图形类 class line (直线)
- main.cpp
-
单元测试设计
主要针对以下函数和情况进行测试:
- getDistance()
- getSlope()
- line->getIntersectWithLine()
- circle->getIntersectWithLine()
- getIntersectWithCircle()
- 当直线与圆相切
- 当直线与直线平行
- 当圆与圆相切
4. 性能分析
可能因为版本原因还未能实现性能分析,会在解决后再进行性能分析并修改博客内容。
5. 代码说明
- 线与线交点
思路:直接套用公式
\[x=\frac{C2\times B1-C1\times B2}{A1\times B2-A2\times B1} \ \ \ \ y=\frac{C1\times A2-C2\times A1}{A1\times B2-A2\times B1}
\]
即可得到直线交点的坐标
void getIntersectWithLine(line another) {
double x = (another.C * B - C * another.B) / (A * another.B - another.A * B);
double y = (C * another.A - another.C * A) / (A * another.B - another.A * B);
intersect_points[make_pair(x, y)] = 1;
}
- 圆与线交点
思路:圆与直线的交点,先判断圆心到直线的距离,看是否有焦点。如果有交点,做直线的垂线,得到垂足,用勾股定理求出弦的长度,然后在垂足的基础上加减向量便得到交点坐标。
void getIntersectWithLine(line Line) {
double A = Line.getA();
double B = Line.getB();
double C = Line.getC();
line newline;
newline.generate_line(B, -A, A * y0 - B * x0);
point center = make_pair(x0, y0);
double dis = Line.getDistance(center);
double x = (newline.getC() * B - C * newline.getB()) / (A * newline.getB() - newline.getA() * B);
double y = (C * newline.getA() - newline.getA()) / (A * newline.getB() - newline.getA() * B);
point foot = make_pair(x, y);
//根据圆心到直线的距离判断是否有交点
if (dis < r) {
// 两个交点
pair<double, double> mini = make_pair(B / sqrt(A * A + B * B), -A / sqrt(A * A + B * B));
double base = sqrt(r * r - dis * dis);
point p1;
p1 = make_pair(foot.first + mini.first * base,
foot.second + mini.second * base);
point p2;
p2 = make_pair(foot.first - mini.first * base,
foot.second - mini.second * base);
intersect_points[p1] = 1;
intersect_points[p2] = 1;
}
else if(dis == r) {
// 垂足为交点
intersect_points[foot] = 1;
}
else { //无交点
return;
}
}
- 圆与圆交点
思路:先判断两圆圆心距离,若小于两圆半径差的绝对值或者大于半径和则都没有交点;否则作垂线,转化为直线与圆的交点,再调用 getIntersectWithLine 函数。
void getIntersectWithCircle(circle another) {
double x1 = another.x0;
double y1 = another.y0;
double r1 = another.r;
if (x0 == x1 && y0 == y1) { //同心
return; //半径相等也记0
}
else {
double dis = sqrt((x1 - x0) * (x1 - x0) +
(y1 - y0) * (y1 - y0));
if (dis <= r + r1 || dis >= abs(r - r1)) { // 外交或内交
line newline;
newline.generate_line(2 * x1 - 2 * x0, 2 * y1 - 2 * y0,
-x1 * x1 + x0 * x0 - y1 * y1 + y0 * y0 + r1 * r1 - r * r);
getIntersectWithLine(newline);
}
}
}