工作中遇到关于多边形地理围栏的工作,主要工作是计算地图上围栏之外的某一点距离多边形围栏的最小距离。
主要思路:点到多边形边界的最短距离,首先求点到多边形每条边的最短距离,然后取这些最短距离的最小值。
点到线段的距离的计算思路:计算点到线段的垂点,如果这个垂点在线段上,那么点到线段的距离就是点到垂点的距离;如果这个垂点不在线段上,那么计算点到线段两个端点的距离的较小值,就作为点到线段的最小距离。
判断垂点是否在线段上的计算方法:垂点到线段的两个端点形成两个向量,这两个向量计算点乘,如果结果为负,那么垂点在线段上;如果结果为正,那么垂点不在线段上。
(采用这种思路计算点到多边形边界的距离暂时没有发现严重的缺陷,但是也没有在所有的情况下都进行验证。)
double QMainWidget::CalDist2Poly( internals::PointLatLng Ppt,internals::PointLatLng Apt,internals::PointLatLng Bpt ) { double disttoline; internals::PointLatLng tmpgeoptp;//飞机的地理坐标点 internals::PointLatLng tmpgeopt0;//0点的地理坐标点 internals::PointLatLng tmpgeopt1;//1点的地理坐标点 internals::PointLatLng tmpgeoptv;//垂点的地理坐标点 core::Point tmpimgptp;//飞机的图像坐标点 core::Point tmpimgpt0;//0点的图像坐标点 core::Point tmpimgpt1;//1点的图像坐标点 core::Point tmpimgptv;//垂点的图像坐标点 float valueA; float valueB; float valueC; tmpgeopt0=Apt; tmpgeopt1=Bpt; tmpgeoptp=Ppt; tmpimgptp=LL2Local(tmpgeoptp); tmpimgpt0=LL2Local(tmpgeopt0); tmpimgpt1=LL2Local(tmpgeopt1); //tmpimgptp.SetY(-tmpimgptp.Y()); //tmpimgpt0.SetY(-tmpimgpt0.Y()); //tmpimgpt1.SetY(-tmpimgpt1.Y()); valueA=tmpimgpt1.Y()-tmpimgpt0.Y(); valueB=tmpimgpt0.X()-tmpimgpt1.X(); valueC=tmpimgpt1.X()*tmpimgpt0.Y()-tmpimgpt0.X()*tmpimgpt1.Y(); float xv=(valueB*valueB*tmpimgptp.X()-valueA*valueB*tmpimgptp.Y()-valueA*valueC)/(valueA*valueA+valueB*valueB); float yv=(-valueA*valueB*tmpimgptp.X()+valueA*valueA*tmpimgptp.Y()-valueB*valueC)/(valueA*valueA+valueB*valueB); int PVx,PVy; if(xv-floor(xv)>=0.50) { PVx=floor(xv+1); } else { PVx=floor(xv); } if(yv-floor(yv)>=0.5) { PVy=floor(yv+1); } else { PVy=floor(yv); } //判断垂点是否在AB这条线段上 如果在这条线段上 那么VA dotproduct VB是小于零的 如果不在这条线段上那么VA dotproduct VB是大于零的 tmpimgptv=core::Point(PVx,PVy); tmpgeoptv=Local2LL(tmpimgptv); QVector2D VAvec=QVector2D(QPoint(tmpimgpt0.X()-tmpimgptv.X(),tmpimgpt0.Y()-tmpimgptv.Y())); QVector2D VBvec=QVector2D(QPoint(tmpimgpt1.X()-tmpimgptv.X(),tmpimgpt1.Y()-tmpimgptv.Y())); double dr=QPoint::dotProduct(QPoint(VAvec.x(),VAvec.y()), QPoint(VBvec.x(),VBvec.y())); if(dr<=0) { disttoline=internals::PureProjection::DistanceBetweenLatLng(tmpgeoptp,tmpgeoptv); } else { double dist1=internals::PureProjection::DistanceBetweenLatLng(tmpgeoptp,tmpgeopt0); double dist2=internals::PureProjection::DistanceBetweenLatLng(tmpgeoptp,tmpgeopt1); if(dist1>=dist2) { disttoline=dist2; } else { disttoline=dist1; } } //tmpgeoptv=Local2LL(tmpimgptv); //disttoline=internals::PureProjection::DistanceBetweenLatLng(tmpgeoptp,tmpgeoptv); return disttoline; }