部分内容参考 http://blog.csdn.net/angelazy/article/details/38489293
1.点到线段的距离
矢量算法
矢量算法过程清晰,如果具有一定的空间几何基础,则是解决此类问题时应优先考虑的方法。当需要计算的数据量很大时,这种方式优势明显。
由于矢量具有方向性,故一些方向的判断直接根据其正负号就可以得知,使得其中的一些问题得以很简单的解决。
用此方法考虑,我们只需要找到向量 在 方向上的投影,具体如下:
上面的 是 方向上的单位向量,其意义是给所求向量确定方向。 是的两个向量的内积,且 ,其中θ为向量AP与AB之间的夹角。 是向量长度。
那么 即为上图中线段AC的长度值,不带有方向性。此数值与上述表征方向的 整体构成有大小、有方向的新向量 ,即为 在 方向上的投影向量,C为投影点。
根据得到的 ,由向量的方向性可知:如果情况是上图(a)所示,那么0<r<1;如果是如图(b)所示的情况,那么r ≥1;如果是如图(c)所示的情况,那么得到r ≤0;
特殊情况如点在线段上、点在端点、点在线段延长线上等等的情况全部适用于此公式,只是作为特殊情况出现,无需另作讨论。这也是矢量算法思想的优势所在。
故根据r值的不同,最短距离

代码如下 :
- double PointTOline( point_t const&a,point_t const&b,point_t const&p){
- double ap_ab = (b.x - a.x)*(p.x - a.x)+(b.y - a.y)*(p.y - a.y);//cross( a , p , b );
- if ( ap_ab <= 0 )
- return sqrt( (p.x-a.x)*(p.x-a.x) + (p.y-a.y)*(p.y-a.y) );
-
- double d2 = ( b.x - a.x ) * ( b.x - a.x ) + ( b.y-a.y ) * ( b.y-a.y ) ;
- if ( ap_ab >= d2 ) return sqrt( (p.x - b.x )*( p.x - b.x ) + ( p.y - b.y )*( p.y - b.y ) ) ;
-
- double r = ap_ab / d2;
- double px = a.x + ( b.x - a.x ) *r;
- double py = a.y + ( b.y - a.y ) *r;
- return sqrt( (p.x - px)*(p.x - px) + (p.y - py)*(p.y - py) );
- }
2. 点在简单多边形内,
(1) 如果多边形是凸多边形,可用叉积法,先graham逆时针排序,然后旋转一周,判断方向是否一致

如图,点在凸包内,方向一定一致的。
(2)凹包要用射线法判断;
给定点A与简单多边形P[N],判断A是否在P上
从A向右做射线,如果射线与P的边有奇数个交点,A在P上,否则A在P外
剔除几种特殊情况
·水平边不判断
·点在边上直接给结论
·点与边的交点恰好是端点,则只计数y值大的那个端点
代码如下
- /*
- * 点与简单多边形相交,使用射线法,剔除三种特殊情况后,判断交点的奇偶
- * 从0开始标号
- × 注意n <= 2 的时候
- */
- struct point_t{
- int x,y;
- };
- bool isOnline( point_t const&a,point_t const&b, point_t const&po ){
- return po.x >= min( a.x , b.x ) &&
- po.x <= max( a.x , b.x ) &&
- po.y >= min( a.y , b.y ) &&
- po.y <= max( a.y , b.y ) &&
- ( po.x - a.x ) * ( b.y - a.y ) == ( po.y - a.y ) * ( b.x - a.x );
- }
- bool isInSimple( point_t * p ,int n , point_t const&po ){
-
- p[n] = p[0];
- bool flag = 0;
- int tmp;
- for ( int i = 0; i < n;++i ){
- if ( isOnline( p[i] , p[i+1] , po ) ) return true;
- if ( p[i].y == p[i+1].y ) continue;
- p[i].y < p[i+1].y ? tmp = i+1 : tmp = i ;
- if ( po.y == p[tmp].y && po.x < p[tmp].x ) flag ^= 1;
- p[i].y > p[i+1].y ? tmp = i+1 : tmp = i ;
- if ( po.y == p[tmp].y && po.x < p[tmp].x ) continue ;
-
- if ( po.x < max( p[i].x , p[i+1].x ) &&
- po.y > min( p[i].y , p[i+1].y ) &&
- po.y < max( p[i].y , p[i+1].y ) ) flag ^= 1;
- }
- return flag;
- }
3.点与凸多边形的距离
先判断是否在多边形内,在求出到每条边的距离
代码如下
- #include <bits/stdc++.h>
- using namespace std;
-
- struct point_t {
- double x,y;
- };
- double cross(point_t const &O,point_t const &A,point_t const &B){
- double xOA = A.x - O.x;
- double yOA = A.y - O.y;
- double xOB = B.x - O.x;
- double yOB = B.y - O.y;
- return xOA * yOB - xOB * yOA;
- }
- double PointTOline( point_t const&a,point_t const&b,point_t const&p){
- double ap_ab = (b.x - a.x)*(p.x - a.x)+(b.y - a.y)*(p.y - a.y);//cross( a , p , b );
- if ( ap_ab <= 0 )
- return sqrt( (p.x-a.x)*(p.x-a.x) + (p.y-a.y)*(p.y-a.y) );
-
- double d2 = ( b.x - a.x ) * ( b.x - a.x ) + ( b.y-a.y ) * ( b.y-a.y ) ;
- if ( ap_ab >= d2 ) return sqrt( (p.x - b.x )*( p.x - b.x ) + ( p.y - b.y )*( p.y - b.y ) ) ;
-
- double r = ap_ab / d2;
- double px = a.x + ( b.x - a.x ) *r;
- double py = a.y + ( b.y - a.y ) *r;
- return sqrt( (p.x - px)*(p.x - px) + (p.y - py)*(p.y - py) );
- }
-
- bool isOnline( point_t const&a,point_t const&b, point_t const&po ){
- return po.x >= min( a.x , b.x ) &&
- po.x <= max( a.x , b.x ) &&
- po.y >= min( a.y , b.y ) &&
- po.y <= max( a.y , b.y ) &&
- ( po.x - a.x ) * ( b.y - a.y ) == ( po.y - a.y ) * ( b.x - a.x );
- }
- bool isInSimple( point_t * p ,int n , point_t const&po ){
- p[n] = p[0];
- bool flag = 0;
- int tmp;
- for ( int i = 0; i < n;++i ){
- if ( isOnline( p[i] , p[i+1] , po ) ) return true;
- if ( p[i].y == p[i+1].y ) continue;
- p[i].y < p[i+1].y ? tmp = i+1 : tmp = i ;
- if ( po.y == p[tmp].y && po.x < p[tmp].x ) flag ^= 1;
- p[i].y > p[i+1].y ? tmp = i+1 : tmp = i ;
- if ( po.y == p[tmp].y && po.x < p[tmp].x ) continue ;
-
- if ( po.x < max( p[i].x , p[i+1].x ) &&
- po.y > min( p[i].y , p[i+1].y ) &&
- po.y < max( p[i].y , p[i+1].y ) ) flag ^= 1;
- }
- return flag;
- }
-
- point_t p[120];
- int main(){
- int n;
- while(cin>>n && n){
- point_t po;
- cin>>po.x>>po.y;
- for (int i = 0;i < n;++i)
- cin>>p[i].x>>p[i].y;
-
- if ( isInSimple( p , n , po ) ) {
- cout <<"0.00"<<endl;
- continue;
- }
- double ans = PointTOline( p[0],p[1],po );
- p[n] = p[0];
- for (int i = 1;i < n ;++i)
- ans = min( ans, PointTOline(p[i] , p[i+1] , po) );
- cout <<ans<<endl;
- }
- return 0;
- }
|