之前写过一篇关于点到直线距离的文章,这回我来研究一下点到线段距离。
回顾一下,推导出的点到直线距离公式为:
详细请见原博客。
分析
在某种情况下,线段外一点P到线段AB的距离可以看做上述P到直线AB的距离:
就像这样子:
但是这样却不行(蓝线为实际距离,红线为到直线距离):
不难看出:
三角形ABP的形状 | 点到线段的距离 |
---|---|
锐角三角形 | P到直线AB的距离 |
直角三角形 | PA,PB的较小者;P到直线AB的距离 |
钝角三角形 | PA,PB的较小者 |
如图所示。
判断三角形的形状
不妨设三边中,最短的两边为a,b,最长边为c。
不难想到,判断直角三角形,就用勾股定理:。
对于锐角三角形:
同理推出,在钝角三角形中,。
接下来,便是令人兴奋的代码了。
代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
double dist(double x1,double x2,double y1,double y2)
{return sqrt(pow(x2-x1,2)+pow(y2-y1,2));}//返回(x1,y1),(x2,y2)之间的距离
int main()
{
double x1,x2,x3,y1,y2,y3;
/*A(x1,y1)
B(x2,y2)
P(x3,y3)*/
cin>>x1>>y1>>x2>>y2>>x3>>y3;
//判断三角形形状
double a,b,c,d;
a=dist(x1,x2,y1,y2);
b=dist(x2,x3,y2,y3);
c=dist(x1,x3,y1,y3);
if(c<a or c<b)
{
if(c<a)
{
int t=a;
a=c;
c=t;
}
if(c<b)
{
int t=b;
b=c;
c=t;
}
}
if(a*a+b*b<=c*c)//直角三角形或钝角三角形
d=min(dist(x1,x3,y1,y3),dist(x2,x3,y2,y3));
else
d=sqrt(pow((x3-x1)*(y2-y1)+(y3-y1)*(x1-x2),2)/(pow(y2-y1,2)+pow(x1-x2,2)));
printf("%.3lf",d);
return 0;
}
但是... ...
有2个测试点没过。80分。
是哪儿出了问题呢?
#以下是改来改去的过程。比较乱。请选择性阅读。#
[灵光一闪] 哦!会不会是没考虑到点在线段(所在直线)上的情况呢?
返回判断三角形的那一步,我们考虑一下这种情况。
让我来改一下代码。
if(a*a+b*b<=c*c)//直角三角形或钝角三角形
{
d=min(dist(x1,x3,y1,y3),dist(x2,x3,y2,y3));
if(a+b==c)//点在线段上
d=0;
}
在此做修改(原代码36行)。
看看对不对呢......?!
Emmm mmmm mmmm... ... ...(不要急不要急不要急)
[灵光再现] 我使了个坏。看到锐角三角形部分有些乱,会不会是那里错了?
于是我把else后面的计算部分删了,交了上去。
哈哈哈哈!找到了!还是80分,也就是说,是else后的计算错了!
让我来换个思路。
由于d是P垂直AB的长度,即AB边上的高,所以通过面积法即可求出!
不知道大家知不知道,有一条根据边长计算面积的公式,叫海伦公式。
于是,求出面积,除以AB即可。
if(a*a+b*b>c*c)
{
int p=(dist(x1,x2,y1,y2)+dist(x1,x3,y1,y3)+dist(x3,x2,y3,y2));
int s=sqrt(p*(p-dist(x1,x2,y1,y2))*(p-dist(x3,x2,y3,y2))*(p-dist(x1,x3,y1,y3)));
d=s/dist(x1,x2,y1,y2);
}
。。。还是80分。(烂尾警告)
等我!我会搞好的!