线段相交与射影坐标

本文探讨了如何判断线段相交的问题,使用了跨立实验和排斥实验的方法。通过射影坐标的概念,阐述了点、直线的关系,并介绍了如何计算直线交点和点在直线上的垂点。此外,还提到了三点共线和三线共点的条件,以及射影坐标在矩阵运算中的局限性。最后提到了求线段集交点集的算法复杂性和poj1066问题,以及如何判断直线关系和求交点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

判断线段相交

跨立实验+排斥实验

排斥:矩形相交

跨立:叉积判点位置

射影坐标

点X(x,y,1)
直线U(a,b,c)(一般式)


两点求直线X1 X X2
直线交点 U1 X U2(无交点即x3=0)
点在直线上 X * U=0


过X的U的垂线 X X U(有待商榷,感觉有问题,但陈可卿ppt是这么写的)
X在U上的垂点 (X X U)X U


过X的U的垂线,自己推了一下,应该是X X (X沿U的法向量移动的一个点,U的法向量为(a,b))


三点共线(X1 X X2)*X3=0
三线共点(U1 X U2)*U3=0


射影坐标看起来很好用,但是它不是定量研究,更多是关于比值的,到后来的矩阵运算就令人难以接受了。


求线段集的交点集(还没抽时间实现)

交点一般情况下不是n^2的,所以有mlogn算法(m为交点数)

沿x轴方向从左到右,碰到端点和交点都是调度事件
碰到一个新的开始端点,只要求它与在y轴上相邻两条线段的交点即可。如果它和其它非相邻线段有交点,随着扫描点的右移,肯定有机会求交点
碰到下一个交点之前,线段在扫描线上的次序不变;碰到一个交点,则交点对应的两条线段交换扫描线上的次序
碰到下一个结束端点,则需要删除它所在的线段

比较抽象,画图比较好懂,百度文库中有此ppt


poj1066

每条线段中点为门,问进入矩形中特定点,最少经过几个点

#include <cstdio>
#include <cstdlib>
#include <cstring>
//#include <cmath>

struct point
{
       double x,y;
};
struct line
{
       int x1,x2,y1,y2;
};

const double eps=1e-6;
line a[100];
point aa,yo;
int n,ans,c[6];
int b[6][100];
const int oo=1073741819;

/*int eps(double x)
{
    if (x > 1e-6) return 1;
    if (x < -1e-6) return -1;
    return 0;
}*/

int cmp(const void *i,const void *j)
{
     return /*eps*/(*(int *)i - *(int *)j);
 }

double cro(point a,point b,point c)
{
    point e,r;
    e.x=b.x-a.x;e.y=b.y-a.y;
    r.x=c.x-a.x;r.y=c.y-a.y;
    return (e.x*r.y)-(e.y*r.x);
}

double max(double x,double y)
{
    return (x>y) ? x :y;
}

double min(double x,double y)
{
    return (x<y) ? x :y;
}

double inter(point a,point b,point c,point d)
{
    return max(a.x,b.x)>=min(c.x,d.x)&&
           max(a.y,b.y)>=min(c.y,d.y)&&
           max(c.x,d.x)>=min(a.x,b.x)&&
           max(c.y,d.y)>=min(a.y,b.y)&&
           cro(a,c,b) * cro(a,b,d) >= 0
		&& cro(c,a,d) * cro(c,d,b) >= 0;
/*           cro(a,b,c)*cro(a,b,d)<=eps  &&
           cro(c,d,b)*cro(c,d,a)<=eps  ;*/		
}

int check(point b1,point b2)
{
    int tot=0;
    point a1,a2;
    int i;
    for (i=1;i<=n;i++)
    {
        a1.x=a[i].x1;a1.y=a[i].y1;
        a2.x=a[i].x2;a2.y=a[i].y2;
        if (inter(a1,a2,b1,b2)) tot++;
    }
    return tot;
}

void init()
{
     scanf("%d\n",&n);
     int i;
     for (i=1;i<=n;i++)
     {
         scanf("%d%d%d%d\n",&a[i].x1,&a[i].y1,&a[i].x2,&a[i].y2);
         if (!((((a[i].x1==a[i].x2)&&(a[i].x1==0))||((a[i].x1==a[i].x2)&&(a[i].x1==100)))||
              (((a[i].y1==a[i].y2)&&(a[i].y1==0))||((a[i].y1==a[i].y2)&&(a[i].y1==100)))))
{         if (0==a[i].x1) b[1][++c[1]]=a[i].y1;
         if (100==a[i].x1) b[2][++c[2]]=a[i].y1;
         if (0==a[i].y1) b[3][++c[3]]=a[i].x1;
         if (100==a[i].y1) b[4][++c[4]]=a[i].x1;
         if (0==a[i].x2) b[1][++c[1]]=a[i].y2;
         if (100==a[i].x2) b[2][++c[2]]=a[i].y2;
         if (0==a[i].y2) b[3][++c[3]]=a[i].x2;
         if (100==a[i].y2) b[4][++c[4]]=a[i].x2;         
}
     }
     scanf("%lf%lf\n",&yo.x,&yo.y);
//     printf("%f %f\n",yo.x,yo.y);
     if (0==n) 
     {
              printf("Number of doors = %d",1);
              return ;
     }
     qsort(b[1]+1,c[1],sizeof(b[1][1]),cmp);
     qsort(b[2]+1,c[2],sizeof(b[2][1]),cmp);
     qsort(b[3]+1,c[3],sizeof(b[3][1]),cmp);          
     qsort(b[4]+1,c[4],sizeof(b[4][1]),cmp); 
     int tot;
     b[1][++c[1]]=100;
     b[2][++c[2]]=100;
     b[3][++c[3]]=100;
     b[4][++c[4]]=100;
     ans=oo;
     for (i=0;i<c[1];i++)    
     {
         aa.x=0.0;aa.y=((double)b[1][i+1]+b[1][i])/2;
         tot=check(aa,yo);
         if (tot<ans) ans=tot;
     }
     for (i=0;i<c[2];i++)    
     {
         aa.x=100.0;aa.y=((double)b[2][i+1]+b[2][i])/2;
         tot=check(aa,yo);
         if (tot<ans) ans=tot;
     }
     for (i=0;i<c[3];i++)    
     {
         aa.x=((double)b[3][i+1]+b[3][i])/2;aa.y=0.0;
         tot=check(aa,yo);
         if (tot<ans) ans=tot;
     }          
     for (i=0;i<c[4];i++)    
     {
         aa.x=((double)b[4][i+1]+b[4][i])/2;aa.y=100.0;
         tot=check(aa,yo);
         if (tot<ans) ans=tot;
     }
     printf("Number of doors = %d",ans+1);     
 }

int main()
{
    freopen("1066.in","r",stdin);
    freopen("1066.out","w",stdout);
     init();
    return 0;
}

poj 1269

判断直线关系是重合,平行,还是相交(并求交点)。

射影坐标让解析流变得冗长。

#include <cstdio>
include <cstdlib>
struct point
{
       int x,y,z;
};
point a,b,c,d,e,l,r;
int n;
void cross(point &a,point b,point c)
{
     a.x=(b.y*c.z)-(b.z*c.y);
     a.y=(b.z*c.x)-(b.x*c.z);
     a.z=(b.x*c.y)-(b.y*c.x);
 }
void init()
{
     scanf("%d%d%d%d",&a.x,&a.y,&b.x,&b.y);
     a.z=1;b.z=1;
     scanf("%d%d%d%d",&c.x,&c.y,&d.x,&d.y);     
     c.z=1;d.z=1;
     cross(l,a,b);cross(r,c,d);cross(e,l,r);
     if ((0==e.x)&&(0==e.y)&&(0==e.z)) {printf("LINE\n");return ;}
     if (0==e.z){ printf("NONE\n");return ;}
     double x=(double)e.x/e.z,y=(double)e.y/e.z;
     printf("POINT %.2lf %.2lf\n",x,y);
 }
int main()
{
    freopen("1269.in","r",stdin);
    freopen("1269.out","w",stdout);
    printf("INTERSECTING LINES OUTPUT\n");
    scanf("%d",&n);
    for (int i=1;i<=n;i++) init();
    printf("END OF OUTPUT\n");
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值