个人项目作业
写在前面:
项目 | 内容 |
---|---|
这个作业属于哪个课程 | 2020年春季计算机学院软件工程(罗杰 任建) |
这个作业的要求在哪里 | 个人项目作业 |
教学班级 | 005 |
项目Github链接 | https://github.com/ame-lm/SEC_HW_IndividualProject |
项目PSP表格:
PSP2.1 | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|
Planning | 60 | 60 |
· Estimate | 30 | 30 |
Development | 420 | 600 |
· Analysis | 20 | 20 |
· Design Spec | 20 | 20 |
· Design Review | 20 | 20 |
· Coding Standard | 20 | 20 |
· Design | 40 | 100 |
· Coding | 240 | 300 |
· Code Review | 30 | 60 |
· Test | 60 | 120 |
Reporting | 40 | 40 |
· Test Report | 20 | 20 |
· Size Measurement | 10 | 10 |
· Postmortem & Process Improvement Plan | 10 | 10 |
解题思路
按照直线和直线, 直线和圆, 圆和圆在平面上的关系分为下面三种情况考虑:
直线和直线:
- 判断直线是否相交: (A_1*B_2-A_2*B_1!=0)则相交.
- 若相交则求交点: ((frac{B_1*C_2-B_2*C_1}{A_1*B_2-A_2*B_1},frac{A_2*C_1-A_1*C_2}{A_1*B_2-A_2*B_1}))
直线和圆:
- 联立直线和圆方程(为了起见简便, 若(B!=0), 化为斜截式再联立), 求得系数(tA), (tB), (tC).
- 根据(Delta=tB^2-4*tA*tC)判断交点个数
- 若(Deltage0) , 根据求根公式求得交点横坐标, 进而求出交点.
圆和圆:
- 计算圆心距(dis=sqrt{(x_1-x_2)^2+(y_1-y_2)^2}).
- 比较圆心距(dis) 和半径和(r_1+r_2), 半径差(|r_1-r_2|) .
- 若有交点则两圆相减求出相交弦方程, 进而转化为直线和圆得交点.
程序设计
对象建模:
平面: Class PlaneContainer
几何图形: Class Figure
交点: Class Point
直线: Class Line: Figure
圆: Class Circle: Figure
交互逻辑:
Class Point重载<
, ==
以适应set
模板.
Class Figure子类均需实现set<Point> ClassName::intersect(Figure* figure)
方法用于计算交点.
Class PlaneContainer实现void PlaneContainer::insert(Figure* figure)
方法用于添加Figure, 每次添加均需和平面内已有图形求交点.
Class PlaneContainer每次添加Figure得到的点放入set<Point> intersectionPoints
中, 借助set
类型过滤相同点.
单元测试
分成两类测试:
测试简单几何对象:
TEST_METHOD(Test1) {//for Circle.cpp, Line.cpp, Figure.cpp, Point.cpp
Point* p1 = new Point(1, 0);
Point* p2 = new Point(100000, 0);
Point* p3 = new Point(1, -100000);
Point* p4 = new Point(-100000, 100000);
Assert::AreNotEqual((int)p1, NULL);
Assert::AreNotEqual((int)p2, NULL);
Assert::AreNotEqual((int)p3, NULL);
Assert::AreNotEqual((int)p4, NULL);
Circle* c1 = new Circle(0, 0, 1);
Circle* c2 = new Circle(-100000, 100000, 100000);
Assert::AreNotEqual((int)c1, NULL);
Assert::AreNotEqual((int)c2, NULL);
Line* l1 = new Line(0, 0, 1, 100000);
Line* l2 = new Line(100000, 0, 1, 100000);
Line* l3 = new Line(0, 0, -100000, 100000);
Line* l4 = new Line(0, -334, 1, 100000);
Assert::AreNotEqual((int)l1, NULL);
Assert::AreNotEqual((int)l2, NULL);
Assert::AreNotEqual((int)l3, NULL);
Assert::AreNotEqual((int)l4, NULL);
}
测试几何对象在平面上相交情况:
包括直线与圆相离, 相交, 相切等测试.
TEST_METHOD(Test2) {//for PlaneContainer.cpp
//test for condition1: all objs are lines
PlaneContainer* pc1 = new PlaneContainer();
Assert::AreEqual(pc1->countIntersectionPoints(), 0);
Line* l1 = new Line(0, 1, 0);
pc1->insert(l1);
Assert::AreEqual(pc1->countIntersectionPoints(), 0);
Line* l2 = new Line(1, 0, 0);
pc1->insert(l2);
Assert::AreEqual(pc1->countIntersectionPoints(), 1);
Line* l3 = new Line(1, 1, 1);
pc1->insert(l3);
Assert::AreEqual(pc1->countIntersectionPoints(), 3);
Line* l4 = new Line(1, 1, -1);
pc1->insert(l4);
Assert::AreEqual(pc1->countIntersectionPoints(), 5);
Line* l5 = new Line(1, -1, 1);
pc1->insert(l5);
Assert::AreEqual(pc1->countIntersectionPoints(), 5);
Line* l6 = new Line(1, -1, -1);
pc1->insert(l6);
Assert::AreEqual(pc1->countIntersectionPoints(), 5);
//test for condition2: all objs are circles
PlaneContainer* pc2 = new PlaneContainer();
Assert::AreEqual(pc2->countIntersectionPoints(), 0);
Circle* c1 = new Circle(0, 0, 1);
pc2->insert(c1);
Assert::AreEqual(pc2->countIntersectionPoints(), 0);
Circle* c2 = new Circle(1, 0, 1);
pc2->insert(c2);
Assert::AreEqual(pc2->countIntersectionPoints(), 2);
Circle* c3 = new Circle(0, 1, 1);
pc2->insert(c3);
Assert::AreEqual(pc2->countIntersectionPoints(), 6);
Circle* c4 = new Circle(-1, 0, 1);
pc2->insert(c4);
Assert::AreEqual(pc2->countIntersectionPoints(), 9);
Circle* c5 = new Circle(0, -1, 1);
pc2->insert(c5);
Assert::AreEqual(pc2->countIntersectionPoints(), 13);
Circle* c6 = new Circle(0, 0, 2);
pc2->insert(c6);
Assert::AreEqual(pc2->countIntersectionPoints(), 17);
//test for condition3: objs contains lines and circles
PlaneContainer* pc3 = new PlaneContainer();
pc3->insert(l1);
pc3->insert(l2);
pc3->insert(l3);
pc3->insert(l4);
pc3->insert(l5);
pc3->insert(l6);
Assert::AreEqual(pc3->countIntersectionPoints(), 5);
pc3->insert(c1);
Assert::AreEqual(pc3->countIntersectionPoints(), 5 + 0);
pc3->insert(c2);
Assert::AreEqual(pc3->countIntersectionPoints(), 5 + 2 + 5);
}
关键代码
Class Line求解相交:
set<Point> Line::intersect(Figure* figure) {
double x, y;
set<Point> points;
if (typeid(*figure) == typeid(Line)) {//line-line condition
Line* line = (Line*)figure;
double A1, B1, C1, A2, B2, C2;
//line1 cofficient
A1 = this->A; B1 = this->B; C1 = this->C;
//line2 cofficient
A2 = line->getA(); B2 = line->getB(); C2 = line->getC();
//cordinate formula:((B1*C2-B2*C1)/(A1*B2-A2*B1),(A2*C1-A1*C2)/(A1*B2-A2*B1))
if (A1 * B2 != A2 * B1) {//not paralell
x = (B1 * C2 - B2 * C1) / (A1 * B2 - A2 * B1);
y = (A2 * C1 - A1 * C2) / (A1 * B2 - A2 * B1);
points.insert(Point(x, y));
}
} else if (typeid(*figure) == typeid(Circle)) {//line-circle condition
Circle* circle = (Circle*)figure;
double tA, tB, tC, a, b, r, k, m, Delta;
//circle cofficient
a = circle->getX();
b = circle->getY();
r = circle->getR();
if (B != 0) {//if line slope exists
//line slope and intercept
k = -A / B;
m = -C / B;
//body equation cofficients
//tA=1+k^2
tA = 1 + k * k;
//tB=2(km-bk-a)
tB = 2 * (k * m - b * k - a);
//tC=a^2+(b-m)^2-r^2
tC = a * a + (b - m) * (b - m) - r * r;
Delta = tB * tB - 4 * tA * tC;
if (Delta > 0) {//intersection
x = (-tB + sqrt(Delta)) / (2 * tA);
y = k * x + m;
points.insert(Point(x, y));
x = (-tB - sqrt(Delta)) / (2 * tA);
y = k * x + m;
points.insert(Point(x, y));
} else if (Delta == 0) {//tangent
x = -tB / (2 * tA);
y = k * x + m;
points.insert(Point(x, y));
}
} else {//line slope not exists
x = m = -C / A;
y = b + sqrt(r * r - (m - a) * (m - a));
points.insert(Point(x, y));
y = b - sqrt(r * r - (m - a) * (m - a));
points.insert(Point(x, y));
}
}
return points;
}
Class Circle求解相交:
set<Point> Circle::intersect(Figure* figure) {
double x, y;
set<Point> points;
if (typeid(*figure) == typeid(Line)) {
//transform circle-line condition into line-circle conditon
Line* line = (Line*)figure;
points = line->intersect(this);
} else if (typeid(*figure) == typeid(Circle)) {
Circle* circle = (Circle*)figure;
double x1, x2, y1, y2, r1, r2;
double D1, D2, E1, E2, F1, F2, dis;
//circle1 cofficient
x1 = this->x;
y1 = this->y;
r1 = this->r;
//circle2 cofficient
x2 = circle->getX();
y2 = circle->getY();
r2 = circle->getR();
//center distance
dis = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
dis = sqrt(dis);
//normal formula of circle
D1 = -2 * x1;
E1 = -2 * y1;
F1 = x1 * x1 + y1 * y1 - r1 * r1;
D2 = -2 * x2;
E2 = -2 * y2;
F2 = x2 * x2 + y2 * y2 - r2 * r2;
if (dis <= r1 + r2 && dis >= abs(r1 - r2)) {
//quation about the intersection string and then transformed into line-circle condition
points = Line(D1 - D2, E1 - E2, F1 - F2).intersect(this);
}
}
return points;
}