交点计数 -- 软工个人项目作业

PSP 2.1

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

解题思路

基本问题

直线公式

对于复杂问题而言,我们首先寻求将问题简化。我们将问题简化到求两条直线的交点。

由解析几何的知识我们知道,通过两条直线的公式可以求出他们的交点。为了简化问题,我使用直线的一般式来表示直线: Ax+By+C = 0.

A,B,C 可以由题目中给定的两点坐标计算得出(设两点为 (x_1,y_1),(x_2,y_2) ):

  • A=y_2−y_1
  • B=x_1−x_2
  • C=x_2y_1−x_1 y_2
交点的计算方法

通过联立上述直线公式,我们可以得到两条直线的交点。

交点x = {B_1C_2-B_2C_1} / {A_1 * B_2-B_1 * A_2}

交点y = {A_2 * C_1-C_2 * A_1} / {A_1 * B_2-B_1 * A_2}

存储方法

我们选用Vector存储过程中产生的交点。在所有交点计算完毕后,我们对数组内元素排序,并去重。

复杂度

由于在获得直线交点时,需要枚举两条直线的所以可能。所以时间复杂度为O(n^2)

设计和实现过程

本设计中包含两个类(直线、圆)和一个结构体(坐标)。结构体作为坐标的数据结构,具有比较等功能。而两个类中都有和其他对象判断交点的方法。主函数通过对每个直线、每个圆建立相应对象,再枚举调用交点计算方法即可找出所有的交点。

交点

stuct Position {
	double x;
	double y;
};

由于我们在后续需要对交点进行排序去重处理,所以我构造和posCompare,posEqual两个函数来比较两个交点的大小和是否相等。

直线:

在直线类中我们存储直线一般式的三个参数\(A,B,C\)

直线可以相交,我们为直线构造相交方法,返回交点结构体。

Class Line {
	long long a, b, c;
	Line(long long x1, long long y1, long long x2, long long y2);
	struct Position intersect(Line&);
}

的类中,我们存储能够定位一个圆的三个参数:\(x,y,r\),即圆心和半径。

同时圆的类中,包含圆与直线相交、圆与圆相交的方法。

class Circle 
{
public:
	Circle(long long x, long long y, long long r);
	long long x, y, r;
	void lineIntersect(const Line&, vector<struct Position>&);
	void circleIntersect(const Circle&, vector<struct Position>&);
};

在计算直线和圆的交点时,我们采用了点到直线的距离公式。distance = |Ax0+By0+C| / sqrt(A2+B2),如果点到直线的距离大于半径,则不会有交点,如果小于或等于半径,则会有0或1个交点。而圆和圆之间的交点,我们采用了向量公式法来进行计算。

性能分析

在本节中我们对代码进行了性能分析。通过随机生成的2000条直线进行测试。从图中可以看出,我们代码的主要耗时部分在于去重时对代码进行的排序操作,占到了所有消耗的80%左右。对于重复结点的删除,我们有两种可以选择的方法,一种是进入时检查,即使用set等维护一个互不重复的结点结合,另一种是输出时检查,此时我们需要额外进行去重处理。二者都需要消耗额外的时间,目前还没有一个很好地降低时间复杂度的方法。


测试

单元测试设计

单元测试主要针对结点的比较函数和交点的计算方法进行。主要的要求是要考虑所有的情况,例如,要考虑结点比较时可能出现的大于、小于、等于等情况,直线交点计算时的相交、平行、垂直等情况,圆和圆之间的相切、相交、相离等其情况。

消除 Code Quality Analysis 中的所有警告

关键代码说明

交点计算方法

这里直接调用公式即可。注意到笔者在这里整数类型都选取的是long long型,虽然我们的坐标值等变量都不会超过int的范围,但是在整数进行乘法运算时,可能有溢出的风险,所以使用long long能够更保证程序的正确性。

结构体(位置)比较函数

我们使用结构体struct Position来存储交点的坐标。由于在最后我们需要对这些坐标进行去重操作,所以我们需要设置坐标的比较函数,判断二者的大小和相等性。

posted @ 2020-03-10 18:18  Lebway  阅读(199)  评论(3编辑  收藏  举报