判断点在直线段上的方法

看到这个题目,估计很多人都会说,这么简单的问题,还写个日志。呵呵

 

当然,大多人的想法自然是用数学公式来计算了,我也是,而且是用的最笨的方法,看吧:

 

一条直线段由两个点确定,假设他们叫a和c,一个点b在这个线段上的条件是,b到a的距离和b到c的距离之和等于a到c的距离。以下假设在二维平面下。

 

b到a的距离 d1=sqrt((b.x-a.x)*(b.x-a.x) + (b.y-a.y)*(b.y-a.y))

d到c的距离 d2=sqrt((c.x-b.x)*(c.x-b.x) + (c.y-b.y)*(c.y-b.y))

 

a到c的距离 d=sqrt((c.x-a.x)*(c.x-a.c) + (c.y-a.y)*(c.y-a.y))

 

只要 d=d1+d2 就表示点b在a-c线段上;计算机判断嘛,这样肯定不行,大家都知道要判断容差,即:

fabs(d-d1-d2) < epsilon

 

很多人都是这样就完成了判断,包括我。显然,计算效率非常低下。

 

今天看一段代码,里面有个函数也是判断点在直线段上的,但是他的写法很简单,经过推敲,原来如此。

So easy! So quickly!

感谢PolyBoolean的作者Michael Leonov。

 

下面我就来推导一下简单的方法:

 

还是上面的式子,只不过再进一步简化而已。呵呵

 

令 d1=b.x-a.x 

   d2=b.y-a.y

   d3=c.x-b.x

   d4=c.y-b.y

判断条件就可以写为:

sqrt(d1*d1+d2*d2) + sqrt(d3*d3+d4*d4) = sqrt((d1+d3)*(d1+d3) + (d2+d4)*(d2+d4))

 

两边平方:

d1*d1 + d2*d2 + d3*d3 + d4*d4 + 2sqrt((d1*d1+d2*d2)*(d3*d3+d4*d4))

                  = (d1+d3)*(d1+d3) + (d2+d4)*(d2+d4)

                  = d1*d1 + d3*d3 + 2d1*d3 + d2*d2 + d4*d4 + 2d2*d4

==> sqrt((d1*d1+d2*d2)*(d3*d3+d4*d4)) = d1*d3 + d2*d4

 

两边再平方并展开:

 d1*d1*d3*d3 + d2*d2*d4*d4 + d1*d1*d4*d4 + d2*d2*d3*d3

------------   ===========  

                  = d1*d3*d1*d3 + d2*d4*d2*d4 + 2d1*d2*d3*d4

                    -----------   ===========

==> d1*d1*d4*d4 + d2*d2*d3*d3 = 2d1*d2*d3*d4

==> (d1*d4 - d2*d3)^2 = 0

==> d1*d4 - d2*d3 = 0

 

到这里,问题得到了简化。不是么?

 

所以判断条件变成:

fabs(d1*d4 - d2*d3) < epsilon

即:

fabs((b.x-a.x)*(c.y-b.y) - (b.y-a.y)*(c.x-b.x)) < epsilon

 

运算量大幅减少,最重要的是不用开平方了,你懂得。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值