判断两线段是否相交-考研真题

之前在网上看到一篇利用向量内积来判断线段是否相交的例子,自己也曾尝试过去书写这样的算法,但是在书写过程中发现,由于该算法涉及的知识包括向量叉乘和点乘公式以及行列式计算等,导致算法的可读性不强,有些地方难于理解。故利用中学的几何知识重新书写判断线段相交的算法,新的算法运算快捷且简单易懂。下面便是详细介绍:

如题:书写算法判断线段p1p2与线段p3p4是否相交。

核心思想其实非常的简单:这里将判断两线段p1p2与线段p3p4相交分解为判断线段p1p2与直线p3p4是否相交和线段p3p4与直线p1p2是否相交。

如果是直线的话,就好办了。

1、先根据直线上的两点算出直线p1p2和直线p3p4的代数方程;

2、判断点p3和点p4是否分别在直线p1p2的两侧;

3、判断点p1和点p2是否分别在直线p3p4的两侧;

4、如果条件2和3均满足,则两线段相交,否则不想交,最后输出结果。

这里还需要指出的一点是判断点在直线的哪一侧,可以将该点的x坐标代入直线方程计算得到y1,如果点的y坐标大于y1则点在直线上方,否则点在直线的下方。

同理判断两点是否在直线的两侧时,只需判断两点是否一个在上侧,一个在下侧即可。

好了,下面就是完整的代码了。

// 判断两条线段是否相交.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
using namespace std;

struct Point
{
	double x,y;
	Point(double x =0,double y=0):x(x),y(y){}
};

class StraightLine
{
public:
	Point begin,end;
	double k;//斜率
	double b;//截距

public:
	StraightLine(const Point begin,const Point end):begin(begin),end(end)
	{
		k = (begin.y-end.y)/(begin.x-end.x);
		b = begin.y-k*begin.x;
	}
public:
	bool isUpper(Point p);//点在是否在直线上方,如果在直线上或上方均返回true,否则返回false
	bool isCross(Point p1,Point p2);//点p1,p2组成的线段是否穿过直线
};


bool StraightLine::isUpper(Point p)
{
	double y1 = k * p.x + b;
	if(p.y>=y1)
		return true;
	else 
		return false;
}

bool StraightLine::isCross(Point p1,Point p2)
{
	if(p1.x==p2.x&&p1.y==p2.y)return false;//若p1与p2坐标相同则返回false
	if(isUpper(p1))
	{
		//如果p1在直线上方,p2在直线下方则满足条件返回True,否则返回false
		if(!isUpper(p2))
			return true;
		else
			return false;
	}
	else
	{
		//如果p1在直线下方,p2在直线上方则满足条件返回True,否则返回false
		if(isUpper(p2))
			return true;
		else
			return false;
	}
	return false;
}

void isCross(Point p1,Point p2,Point p3,Point p4)
{
	StraightLine Line1(p1,p2);
	StraightLine Line2(p3,p4);
	//若点p3,p4分别在直线p1p2的两侧,且点p3,p4分别在直线p1p2的两侧,则线段p1p2与线段p3p4相交
	if(Line1.isCross(p3,p4)&&Line2.isCross(p1,p2))
	{
		printf("Cross!\n");
	}
	else
	{
		printf("Don't Cross!\n");
	}
}


int _tmain(int argc, _TCHAR* argv[])
{

	Point p1(1,2),p2(5,3),p3(1,5),p4(5,1);
	isCross(p1,p2,p3,p4);

	Point a1(1,3),a2(5,2),a3(2,4),a4(4,9);
	isCross(a1,a2,a3,a4);


	getchar();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值