地图上获取坐标是否在指定区域内,区域外点计算距离区域的最短距离


  1. 坐标是否在指定区域坐标内
    数学模型中,射线法求取射线与多边形交点个数来判断点是否在多边形内,交点为奇数时在多边形内,偶数在多边形外
    判断几种特殊情况,点为多边形上顶点,点在多边形边上,射线与多边形交点是多边形的顶点(多边形的每一个顶点其实是相邻两条线段的端点,所以顶点可以算两个点)
    
    
    /**
     * 给定点和多边形,判断给定的点是否在多边形内
     * @param point
     * @param points
     * @return
     */
    public static boolean IsPtInPoly(Point2D.Double point, List<Point2D.Double> points){
      int N = points.size();
      boolean boundOrVertex = true; //如果点位于多边形的顶点或边上,也算做点在多边形内,直接返回true
      int intersectCount = 0;//cross points count of x
      double precision = 2e-10; //浮点类型计算时候与0比较时候的容差
      Point2D.Double p1, p2;//neighbour bound vertices
      Point2D.Double p = point; //当前点
    
      p1 = points.get(0);//left vertex
      for(int i = 1; i <= N; ++i){//check all rays
        if(p.equals(p1)){
          return boundOrVertex;//p is an vertex
        }
    
        p2 = points.get(i % N);//right vertex
        if(p.x < Math.min(p1.x, p2.x) || p.x > Math.max(p1.x, p2.x)){//ray is outside of our interests
          p1 = p2;
          continue;//next ray left point
        }
    
        if(p.x > Math.min(p1.x, p2.x) && p.x < Math.max(p1.x, p2.x)){//ray is crossing over by the algorithm (common part of)
          if(p.y <= Math.max(p1.y, p2.y)){//x is before of ray
            if(p1.x == p2.x && p.y >= Math.min(p1.y, p2.y)){//overlies on a horizontal ray
              return boundOrVertex;
            }
    
            if(p1.y == p2.y){//ray is vertical
              if(p1.y == p.y){//overlies on a vertical ray
                return boundOrVertex;
              }else{//before ray
                ++intersectCount;
              }
            }else{//cross point on the left side
              double xinters = (p.x - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y;//cross point of y
              if(Math.abs(p.y - xinters) < precision){//overlies on a ray
                return boundOrVertex;
              }
    
              if(p.y < xinters){//before ray
                ++intersectCount;
              }
            }
          }
        }else{//special case when ray is crossing through the vertex
          if(p.x == p2.x && p.y <= p2.y){//p crossing over p2
            Point2D.Double p3 = points.get((i+1) % N); //next vertex
            if(p.x >= Math.min(p1.x, p3.x) && p.x <= Math.max(p1.x, p3.x)){//p.x lies between p1.x & p3.x
              ++intersectCount;
            }else{
              intersectCount += 2;
            }
          }
        }
        p1 = p2;//next ray left point
      }
    
      if(intersectCount % 2 == 0){//偶数在多边形外
        return false;
      } else { //奇数在多边形内
        return true;
      }
    }



  2. 区域外点计算距离区域的最短距离
    获取距离最短的顶点,取以这个顶点为端点的相邻两条线段,计算目标坐标点到两条线段的距离,较小值就为最短距离

    海伦公式,知道三边长得到三角形面积
    先判断三角形是否以中间点为顶点的钝角三角形,是的话返回相应点到点距离
    然后用海伦公式算出高,返回高

    /**
     * luming
     * 点到边的最短距离
     * @param pointP
     * @param pointA
     * @param pointB
     * @return
     */
    public static double minDistanceToLine(Location pointP, Location pointA, Location pointB){
    
      double pa = getDistance(pointP,pointA);
      double pb = getDistance(pointP,pointB);
      double ab = getDistance(pointA,pointB);
    
      if((Math.pow(pa,2) + Math.pow(ab,2)) <= Math.pow(pb,2) ){
        return pa;
      }
      if((Math.pow(pb,2) + Math.pow(ab,2)) <= Math.pow(pa,2) ){
        return pb;
      }
    
      double p = (pa + pb + ab) / 2 ;
      double s = Math.sqrt(p*(p-pa)*(p-pb)*(p-ab));
    
      return (2*s/ab);
    }
    
    
    
    
    /**
     * 通过经纬度获取距离(单位:米)
     * @param lat1
     * @param lng1
     * @param lat2
     * @param lng2
     * @return
     */
    public static double getDistance(double lat1, double lng1, double lat2,
                                     double lng2) {
      double radLat1 = rad(lat1);
      double radLat2 = rad(lat2);
      double a = radLat1 - radLat2;
      double b = rad(lng1) - rad(lng2);
      double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
          + Math.cos(radLat1) * Math.cos(radLat2)
          * Math.pow(Math.sin(b / 2), 2)));
      s = s * EARTH_RADIUS;
      s = Math.round(s * 10000d) / 10000d;
      s = s*1000;
      return s;
    }
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值