判断线段相交
跨立实验+排斥实验
排斥:矩形相交
跨立:叉积判点位置
射影坐标
点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;
}