项目

内容

这个作业属于哪个课程

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,对 斜率相等 的线进行剪枝,即先判断是否平行,若平行则无交点。可以减少一点计算。
  • 对于附加题:
    圆与直线的交点,先判断圆心到直线的距离,看是否有焦点。如果有交点,按照参考 中的方法,做垂线,求出弦的长度,然后在垂足的基础上加减向量。
    圆与圆的交点可以转化为圆与直线的交点。
    参考:

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()
  • 当直线与圆相切
  • 当直线与直线平行
  • 当圆与圆相切

圆和直线交点python求解_ci

4. 性能分析

圆和直线交点python求解_圆和直线交点python求解_02

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

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);
			}
		}
	}