Intersection
Time Limit: 1000MS |
Memory Limit: 10000K |
|
Total Submissions: 7609 |
Accepted: 1989 |
Description
You are to write a program that has to decide whether a given line segment intersects a given rectangle.
An example:
line: start point: (4,9)
end point: (11,2)
rectangle: left-top: (1,5)
right-bottom: (7,1)
Figure 1: Line segment does not intersect rectangle
The line is said to intersect the rectangle if the line and the rectangle have
at least one point in common. The rectangle consists of four straight lines and
the area in between. Although all input values are integer numbers, valid
intersection points do not have to lay on the integer grid.
Input
The input
consists of n test cases. The first line of the input file contains the number
n. Each following line contains one test case of the format:
xstart ystart xend yend xleft ytop xright ybottom
where (xstart, ystart) is the start and (xend, yend) the end point of the line
and (xleft, ytop) the top left and (xright, ybottom) the bottom right corner of
the rectangle. The eight numbers are separated by a blank. The terms top left
and bottom right do not imply any ordering of coordinates.
Output
For each test case in the input file, the output file should contain a line consisting either of the letter "T" if the line segment intersects the rectangle or the letter "F" if the line segment does not intersect the rectangle.
Sample Input
1
4 9 11 2 1 5 7 1
Sample Output
F
Source
Southwestern European Regional Contest 1995
解题报告:这道题就是判断线段是否和矩形相交(含顶点),利用跨立试验判断,其中跨立试验的基本思想如下(网上摘得)跨立试验 :如果两线段相交,则两线段必然相互跨立对方。若P1P2跨立Q1Q2 ,则矢量 ( P1 - Q1 ) 和( P2 - Q1 )位于矢量( Q2 - Q1 ) 的两侧,即( P1 - Q1 ) × ( Q2 - Q1 ) * ( P2 - Q1 ) × ( Q2 - Q1 ) < 0。上式可改写成( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) > 0。当 ( P1 - Q1 ) × ( Q2 - Q1 ) = 0 时,说明 ( P1 - Q1 ) 和 ( Q2 - Q1 )共线,但是因为已经通过快速排斥试验,所以 P1 一定在线段 Q1Q2上;同理,( Q2 - Q1 ) ×(P2 - Q1 ) = 0 说明 P2 一定在线段 Q1Q2上。所以判断P1P2跨立Q1Q2的依据是:( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) >= 0。同理判断Q1Q2跨立P1P2的依据是:( Q1 - P1 ) × ( P2 - P1 ) * ( P2 - P1 ) × ( Q2 - P1 ) >= 0。
代码如下:
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #define Max(x, y)(x > y ? x : y) #define Min(x, y)(x < y ? x : y) using namespace std; int n; bool flag;//标志变量 struct Point { double x; double y; }rec[4], seg[2];//rec数组存储矩形的坐标,seg数组存储线段两点的坐标 double Multi(Point p1, Point p2, Point p3)//叉乘判断点与线的位置关系 { return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y); } //跨立试验,判断两线段是否相交 bool Isintersect(Point a1, Point a2, Point b1, Point b2)//判断两条线段是否相交(含顶点) { if (Min(a1.x, a2.x) <= Max(b1.x, b2.x) && Min(a1.y, a2.y) <= Max(b1.y, b2.y) && Min(b1.x, b2.x) <= Max(a1.x, a2.x) && Min(b1.y, b2.y) <= Max(a1.y, a2.y) && Multi(a1, a2, b1) * Multi(a1, a2, b2) <= 0 && Multi(b1, b2, a1) * Multi(b1, b2, a2) <= 0 ) return true;//说明两线段之间相交 return false; } bool Inrectangle(int i)//判断点是否在矩形的内部 { if (seg[i].x > Max(rec[1].x, rec[3].x)) return false; if (seg[i].y > Max(rec[1].y, rec[3].y)) return false; if (seg[i].x < Min(rec[1].x, rec[3].x)) return false; if (seg[i].y < Min(rec[1].y, rec[3].y)) return false; //如果满足上面的,说明线段在矩形的内部并且没有和矩形没有交点(含线段的顶点) return true; } int main() { int i; scanf("%d", &n); while (n --) { scanf("%lf%lf%lf%lf", &seg[0].x, &seg[0].y, &seg[1].x, &seg[1].y); scanf("%lf%lf%lf%lf", &rec[1].x, &rec[1].y, &rec[3].x, &rec[3].y); rec[0].x = rec[1].x; rec[0].y = rec[3].y; rec[2].x = rec[3].x; rec[2].y = rec[1].y; flag = false;//假设线段和矩形没有相交 if (Inrectangle(0) || Inrectangle(1)) { flag = true; } else { for (i = 0; i < 4; ++i) { if (Isintersect(rec[i], rec[(i + 1) % 4], seg[0], seg[1])) { flag = true;//两线段已经相交了直接退出即可 break; } } } if (flag)//线段和矩形相交 { printf("T\n"); } else { printf("F\n"); } } return 0; }