个人项目博客

项目 内容
这个作业属于哪个课程 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 : 计算与另一个圆的交点
  • 单元测试设计

    主要针对以下函数和情况进行测试:

    • getDistance()
    • getSlope()
    • line->getIntersectWithLine()
    • circle->getIntersectWithLine()
    • getIntersectWithCircle()
    • 当直线与圆相切
    • 当直线与直线平行
    • 当圆与圆相切

    image-20200310202411635

4. 性能分析

image-20200310210737849

可能因为版本原因还未能实现性能分析,会在解决后再进行性能分析并修改博客内容。

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);
			}
		}
	}
posted @ 2020-03-10 18:31  真空快速吸  阅读(251)  评论(2编辑  收藏  举报