两线段相交求交点

算法一

#include<stdio.h>  #include<stdlib.h>  #include<assert.h>

struct POINT  {  int x;  int y;  };

bool IsLineSegmentCross(POINT pFirst1, POINT pFirst2, POINT pSecond1, POINT pSecond2) 

//每个线段的两点都在另一个线段的左右不同侧,则能断定线段相交 
//公式对于向量(x1,y1)->(x2,y2),判断点(x3,y3)在向量的左边,右边,还是线上. 
//p=x1(y3-y2)+x2(y1-y3)+x3(y2-y1).p<0 左侧, p=0 线上, p>0 右侧 
long Linep1,Linep2;  //判断pSecond1和pSecond2是否在pFirst1->pFirst2两侧 
Linep1 = pFirst1.x * (pSecond1.y - pFirst2.y) + pFirst2.x * (pFirst1.y - pSecond1.y) +  pSecond1.x * (pFirst2.y  -pFirst1.y);  Linep2 = pFirst1.x * (pSecond2.y - pFirst2.y) + pFirst2.x * (pFirst1.y - pSecond2.y) +  pSecond2.x * (pFirst2.y - pFirst1.y);  if ( ((Linep1 ^ Linep2) >= 0 ) && !(Linep1==0 && Linep2==0))//符号位异或为0:pSecond1和pSecond2在pFirst1->pFirst2同侧 
{ return false;  }  //判断pFirst1和pFirst2是否在pSecond1->pSecond2两侧 
Linep1 = pSecond1.x * (pFirst1.y - pSecond2.y) +pSecond2.x * (pSecond1.y - pFirst1.y) + pFirst1.x * (pSecond2.y -pSecond1.y);  Linep2 = pSecond1.x * (pFirst2.y - pSecond2.y) + pSecond2.x * (pSecond1.y - pFirst2.y) + pFirst2.x * (pSecond2.y - pSecond1.y);  if ( ((Linep1 ^ Linep2) >= 0 ) && !(Linep1==0 && Linep2==0))//符号位异或为0:pFirst1和pFirst2在pSecond1->pSecond2同侧 
{ return false;  }  //否则判为相交  return true;  }  POINT GetCrossPoint(POINT p1, POINT p2, POINT q1, POINT q2) 
{ //必须相交求出的才是线段的交点,但是下面的程序段是通用的assert(IsLineSegmentCross(p1,p2,q1,q2));  POINT crossPoint;  long tempLeft,tempRight;  //求x坐标  tempLeft = (q2.x - q1.x) * (p1.y - p2.y) - (p2.x - p1.x) * (q1.y - q2.y); 
tempRight = (p1.y - q1.y) * (p2.x - p1.x) * (q2.x - q1.x) + q1.x * (q2.y - q1.y) * (p2.x - p1.x) - p1.x * (p2.y - p1.y) * (q2.x - q1.x); 
crossPoint.x =(int)( (double)tempRight / (double)tempLeft ); 
//求y坐标  tempLeft = (p1.x - p2.x) * (q2.y - q1.y) - (p2.y - p1.y) * (q1.x - q2.x); 
tempRight = p2.y * (p1.x - p2.x) * (q2.y - q1.y) + (q2.x- p2.x) * (q2.y - q1.y) * (p1.y - p2.y) - q2.y * (q1.x - q2.x) * (p2.y - p1.y); 
crossPoint.y =(int)( (double)tempRight / (double)tempLeft ); 
return crossPoint;  }  int main(void)  {  POINT pointA,pointB,pointC,pointD;  POINT pointCross;  bool bCross(false);  pointA.x = 400;pointA.y=440;  pointB.x = 300;pointB.y = 440;  pointC.x = 350;pointC.y = 500;  pointD.x = 350;pointD.y = 400;  bCross = IsLineSegmentCross(pointA,pointB,pointC,pointD);  if (bCross)  {

pointCross = GetCrossPoint(pointA,pointB,pointC,pointD);  printf("交点坐标x=%d,y=%d\n",pointCross.x,pointCross.y);  }  else  { 
printf("They are not crossed!");  }  return 0;  }

算法二

定义:平面上的三点P1(x1,y1),P2(x2,y2),P3(x3,y3)的面积量: 
|x1   x2   x3|
S(P1,P2,P3)   =   |y1   y2   y3|   =   (x1-x3)*(y2-y3)   -   (y1-y3)(x2-x3) 
|1   1  1|
已知一条线段的两个端点为A(x1,y1),B(x2,y2),另一条线段的两个端点为C(x3,y3),D(x4,y4),要判断AB与CD是否有交点,若有求出.
首先判断d   =   (y2-y1)(x4-x3)-(y4-y3)(x2-x1),
若d=0,则直线AB与CD平行或重合,
若d!=0,则直线AB与CD有交点,设交点为E(x0,y0):
则有:CE/ED   =   S(A,C,B)   /   S(A,B,D)
所以:CE/CD   =   S(A,C,B)   /   (S(A,C,B)   +   S(A,B,D))
故   x0   =   C.x   +   (D.x   -   C.x)   *   S(A,C,B)   /   (S(A,C,B)   +   S(A,B,D));
y0   =   C.y   +   (D.y   -   C.y)   *   S(A,C,B)   /   (S(A,C,B)   +   S(A,B,D));
也可以直接求
x0   =   [(x2-x1)*(x4-x3)*(y3-y1)+(y2-y1)*(x4-x3)*x1-(y4-y3)*(x2-x1)*x3]/d
y0   =   [(y2-y1)*(y4-y3)*(x3-x1)+(x2-x1)*(y4-y3)*y1-(x4-x3)*(y2-y1)*y3]/(-d)
求出交点后在判断交点是否在线段上,即判断以下的式子:
(x0-x1)*(x0-x2) <=0
(x0-x3)*(x0-x4) <=0
(y0-y1)*(y0-y2) <=0
(y0-y3)*(y0-y4) <=0
只有上面的四个式子都成立才可判定(x0,y0)是线段AB与CD的交点,否则两线段无交点

算法三

//求两个点的直线方程
LINE makeline(POINT p1,POINT p2) {
LINE tl;
int sign = 1;
tl.a=p2.y-p1.y;
if (tl.a<0) {
sign = -1;
tl.a=sign*tl.a;
}
tl.b=sign*(p1.x-p2.x);
tl.c=sign*(p1.y*p2.x-p1.x*p2.y);
return tl;
}
// 如果两条直线 l1(a1*x+b1*y+c1 = 0), l2(a2*x+b2*y+c2 = 0)相交,返回true,且返回交点p
bool lineintersect(LINE l1,LINE l2,POINT &p) {// 是 L1,L2
double d=l1.a*l2.b-l2.a*l1.b;
if (abs(d)<EP) return false;// 不相交
p.x = (l2.c*l1.b-l1.c*l2.b)/d;
p.y = (l2.a*l1.c-l1.a*l2.c)/d;
return true;
}
//计算叉积
double multiply(POINT sp,POINT ep,POINT op) {
return((sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y));
}
bool online(LINEl,POINT p)
{
return((multiply(l.b,p,l.a)==0)&&(((p.x-l.a.x)*(p.x-l.b.x)<=0)&&((p.y-l.a.y)*(p.y-l.b.y)<=0)));
}

http://blog.sina.com.cn/s/blog_4c4a15950100rhjn.html

转载于:https://www.cnblogs.com/lz-vic/p/4765912.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值