您的位置:首页 > 其它

叉积--求两条直线(线段)的交点

2014-11-08 19:20 381 查看


转载自学长/article/1931733.html

如图,如何求得直线AB和直线CD的交点P?



以上内容摘自《算法艺术与信息学竞赛》。

思路:利用叉积求得点P分线段DC的比,然后利用高中学习的定比分点坐标公式求得分点P的坐标。

看不懂的可以去复习下
定比分点 的知识。

<pre name="code" class="cpp"><span style="font-family:Microsoft YaHei;">#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<string>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
#define Max(a,b) a>b?a:b
#define Min(a,b) a>b?b:a
#define mem(a,b) memset(a,b,sizeof(a))
int dir[4][2]= {{0,-1},{-1,0},{0,1},{1,0}};
#define N 105
const double eps = 1e-6;
const double Pi = acos(-1.0);
struct Point
{
    Point() {}
    Point(double x,double y):x(x),y(y) {}
    double x,y;
};

struct Seg
{
    Point p1,p2;
};

int sgn(double x)
{
    return x<-eps ? -1 : (x>eps);
}

double Cross(const Point& p1,const Point& p2,const Point& p3,const Point& p4)
{
    return (p2.x-p1.x)*(p4.y-p3.y) - (p2.y-p1.y)*(p4.x-p3.x);
}

double Area(const Point& p1,const Point& p2,const Point& p3)
{
    return Cross(p1,p2,p1,p3);
}

double fArea(const Point& p1,const Point& p2,const Point& p3)
{
    return fabs(Area(p1,p2,p3));
}

bool Meet(const Point& p1,const Point& p2,const Point& p3,const Point& p4)
{
    return max(min(p1.x,p2.x),min(p3.x,p4.x)) <= min(max(p1.x,p2.x),max(p3.x,p4.x))
           && max(min(p1.y,p2.y),min(p3.y,p4.y)) <= min(max(p1.y,p2.y),max(p3.y,p4.y))
           && sgn(Cross(p3,p2,p3,p4) * Cross(p3,p4,p3,p1)) >= 0
           && sgn(Cross(p1,p4,p1,p2) * Cross(p1,p2,p1,p3)) >= 0;
}

Point Inter(const Point& p1,const Point& p2,const Point& p3,const Point& p4)
{
    double k = fArea(p1,p2,p3) / fArea(p1,p2,p4);
    return Point((p3.x + k*p4.x)/(1+k),(p3.y + k*p4.y)/(1+k));
}
int main()
{
    int T;
    cin >>T;
    while(T--)
    {
        Point a,b,c,d;
        a.read();
        b.read();
        c.read();
        d.read();
        Inter(a,c, b,d).print();
    }
    return 0;
}
</span>



代码方面,我并没有按照书上的写法来写,而是直接求出“比”k,然后利用通分前的公式计算。
书上那样写可能是因为前面已经求得了两个叉积,直接使用更方便的关系。

下面是书中的写法。

Point Inter(const Point& p1,const Point& p2,const Point& p3,const Point& p4)
{
    double s1 = fArea(p1,p2,p3) , s2 = fArea(p1,p2,p4);
    return Point((p4.x*s1+p3.x*s2)/(s1+s2),(p4.y*s1+p3.y*s2)/(s1+s2));
}

NYOJ例题1132链接:click here

代码:

/*
1)先求一条线段的直线方程,判断另一条线段的两个端点是否在直线的异侧
2)再求另一条线段的直线方程,同上判断;
3)再考虑线段共线的情况,求出重合点;
不共线,用二阶行列式求出交点*/
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<string>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
#define Max(a,b) a>b?a:b
#define Min(a,b) a>b?b:a
#define mem(a,b) memset(a,b,sizeof(a))
int dir[4][2]= {{0,-1},{-1,0},{0,1},{1,0}};
const double eps = 1e-6;
const double Pi = acos(-1.0);
double a,b,c;
double a1,b1,c1,a2,b2,c2;
typedef struct Point
{
    double x;
    double y;
} Point;
Point r;
double min(double a,double b)
{
    if(a<b) return a;
    return b;
}
double max(double a,double b)
{
    if(a>b) return a;
    return b;
}
void GetLine(Point p,Point q)
{
    a=q.y-p.y;
    b=p.x-q.x;
    c=q.x*p.y-p.x*q.y;
}
int flag(Point p1,Point p2,Point q1,Point q2)
{
    double m,n;
    GetLine(p2,q2);
    a2=a,b2=b,c2=-c;
    m=a*p1.x+b*p1.y+c;
    n=a*q1.x+b*q1.y+c;
    if(m*n>0) return 0;
    if(fabs(m)<1e-8&&fabs(n)<1e-8)
    {
        if(fabs(b)<1e-8)
            if(((p1.y<min(p2.y,q2.y)&&q1.y<min(p2.y,q2.y))||(p1.y>max(p2.y,q2.y)&&q1.y>max(p2.y,q2.y)))) return 0;
            else
            {
                if(p1.y==p2.y || p1.y==q2.y)r.x=p1.x,r.y=p1.y;
                else r.x=q1.x,r.y=q1.y;
                return 1;
            }
        if(((p1.x<min(p2.x,q2.x)&&q1.x<min(p2.x,q2.x))||(p1.x>max(p2.x,q2.x)&&q1.x>max(p2.x,q2.x)))) return 0;
        else
        {
            if(p1.x==p2.x || p1.x==q2.x) r.x=p1.x,r.y=p1.y;
            else r.x=q1.x,r.y=q1.y;
            return 1;
        }
    }
    GetLine(p1,q1);
    a1=a,b1=b,c1=-c;
    m=a*p2.x+b*p2.y+c;
    n=a*q2.x+b*q2.y+c;
    if(m*n>0) return 0;
    r.x=(c1*b2-c2*b1)/(a1*b2-a2*b1);
    r.y=(a1*c2-a2*c1)/(a1*b2-a2*b1);
    return 1;
}
int main()
{
    //freopen("1.txt","r",stdin);
    //freopen("2.txt","w",stdout);
    int n;
    Point a,b,c,d;
    scanf("%d",&n);
    while(n--)
    {
        scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&a.x,&a.y,&c.x,&c.y,&b.x,&b.y,&d.x,&d.y);
        {
            if(flag(a,b,c,d)) printf("yes %.1lf %.1lf\n",r.x,r.y);
            else printf("no\n");
        }
    }
    return 0;
}
Ps:

1、求交点之前,要保证两条直线不共线。

2、如果是求两条线段的交点,先判断两条线段是否相交。

若相交,则问题可转化成两条直线求交点。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: