POJ 1410 Intersection(计算几何线段相交跨立试验)

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;
}
原文地址:https://www.cnblogs.com/lidaojian/p/2486600.html