【问题标题】:point to line using angles and haversine with 3 lat long points使用具有 3 个纬度长点的角度和半正弦点到线
【发布时间】:2014-09-07 06:38:34
【问题描述】:

我希望得到一条线的距离并开始使用haversine代码。

 private static final double _eQuatorialEarthRadius = 6378.1370D;
    private static final double _d2r = (Math.PI / 180D);
    private static double PRECISION = 0.001;

    // Haversine Algorithm
    // source: http://stackoverflow.com/questions/365826/calculate-distance-between-2-gps-coordinates

    private static double HaversineInM(double lat1, double long1, double lat2, double long2) {
        return  (1000D * HaversineInKM(lat1, long1, lat2, long2));

    }

    private static double HaversineInKM(double lat1, double long1, double lat2, double long2) {
        double dlong = (long2 - long1) * _d2r;
        double dlat = (lat2 - lat1) * _d2r;
        double a = Math.pow(Math.sin(dlat / 2D), 2D) + Math.cos(lat1 * _d2r) * Math.cos(lat2 * _d2r)
                * Math.pow(Math.sin(dlong / 2D), 2D);
        double c = 2D * Math.atan2(Math.sqrt(a), Math.sqrt(1D - a));
        double d = _eQuatorialEarthRadius * c;

        return d;
    }

    // Distance between a point and a line

    public static double pointLineDistanceTest(double[] aalatlng,double[] bblatlng,double[] ttlatlng) {


        double [] a = aalatlng;
        double [] b = bblatlng;
        double [] c = ttlatlng;


        double[] nearestNode = nearestPointGreatCircle(a, b, c);
//        System.out.println("nearest node: " + Double.toString(nearestNode[0]) + "," + Double.toString(nearestNode[1]));
        double result =  HaversineInM(c[0], c[1], nearestNode[0], nearestNode[1]);
//        System.out.println("result: " + Double.toString(result));


              return (result);


    }

    // source: http://stackoverflow.com/questions/1299567/how-to-calculate-distance-from-a-point-to-a-line-segment-on-a-sphere
    private static double[] nearestPointGreatCircle(double[] a, double[] b, double c[])
    {
        double[] a_ = toCartsian(a);
        double[] b_ = toCartsian(b);
        double[] c_ = toCartsian(c);

        double[] G = vectorProduct(a_, b_);
        double[] F = vectorProduct(c_, G);
        double[] t = vectorProduct(G, F);

        return fromCartsian(multiplyByScalar(normalize(t), _eQuatorialEarthRadius));
    }

    @SuppressWarnings("unused")
    private static double[] nearestPointSegment (double[] a, double[] b, double[] c)
    {
       double[] t= nearestPointGreatCircle(a,b,c);
       if (onSegment(a,b,t))
         return t;

       return (HaversineInKM(a[0], a[1], c[0], c[1]) < HaversineInKM(b[0], b[1], c[0], c[1])) ? a : b;
    }

     private static boolean onSegment (double[] a, double[] b, double[] t)
       {
         // should be   return distance(a,t)+distance(b,t)==distance(a,b), 
         // but due to rounding errors, we use: 
         return Math.abs(HaversineInKM(a[0], a[1], b[0], b[1])-HaversineInKM(a[0], a[1], t[0], t[1])-HaversineInKM(b[0], b[1], t[0], t[1])) < PRECISION;
       }


    // source: http://stackoverflow.com/questions/1185408/converting-from-longitude-latitude-to-cartesian-coordinates
    private static double[] toCartsian(double[] coord) {
        double[] result = new double[3];
        result[0] = _eQuatorialEarthRadius * Math.cos(Math.toRadians(coord[0])) * Math.cos(Math.toRadians(coord[1]));
        result[1] = _eQuatorialEarthRadius * Math.cos(Math.toRadians(coord[0])) * Math.sin(Math.toRadians(coord[1]));
        result[2] = _eQuatorialEarthRadius * Math.sin(Math.toRadians(coord[0]));


        return result;
    }

    private static double[] fromCartsian(double[] coord){
        double[] result = new double[2];
        result[0] = Math.toDegrees(Math.asin(coord[2] / _eQuatorialEarthRadius));
        result[1] = Math.toDegrees(Math.atan2(coord[1], coord[0]));

        return result;
    }


    // Basic functions
    private static double[] vectorProduct (double[] a, double[] b){
        double[] result = new double[3];
        result[0] = a[1] * b[2] - a[2] * b[1];
        result[1] = a[2] * b[0] - a[0] * b[2];
        result[2] = a[0] * b[1] - a[1] * b[0];

        return result;
    }

    private static double[] normalize(double[] t) {
        double length = Math.sqrt((t[0] * t[0]) + (t[1] * t[1]) + (t[2] * t[2]));
        double[] result = new double[3];
        result[0] = t[0]/length;
        result[1] = t[1]/length;
        result[2] = t[2]/length;
        return result;
    }

    private static double[] multiplyByScalar(double[] normalize, double k) {
        double[] result = new double[3];
        result[0] = normalize[0]*k;
        result[1] = normalize[1]*k;
        result[2] = normalize[2]*k;
        return result;
    }

并且有很多错误所以写这个来计算使用方位角得到角度然后使用距离(点 a,目标)计算目标到(点 a,点 b)线。 A点和B点是线,我想要从目标到线的距离。没有大圈。 sin角(方位差)*点a到目标距离=直角三角形的边从AB线上的直角到目标的长度。

 public  double pointlinedistancetest(){

     //set latlng location point a
     Location apoint=new Location("");

     apoint.setLatitude(lata);
     apoint.setLongitude(lona);


     //set latlng location point b
     Location bpoint=new Location("");

     bpoint.setLatitude(latb);
     bpoint.setLongitude(lonb);


     //set latlng location target to get dis to line
     Location tpoint=new Location("");

     tpoint.setLatitude(lat);
     tpoint.setLongitude(lon);


     float pbearingf = apoint.bearingTo(bpoint);

     float tbearingf= apoint.bearingTo(tpoint);

     double tb=tbearingf;
     double ab=pbearingf;



             //get angle degree difference 
    float angle= Math.min((pbearingf-tbearingf)<0?pbearingf-tbearingf+360:pbearingf-tbearingf, (tbearingf-pbearingf)<0?tbearingf-pbearingf+360:tbearingf-pbearingf);
//   float angle= Math.min((tbearingf-pbearingf)<0?tbearingf-pbearingf+360:tbearingf-pbearingf, (pbearingf-tbearingf)<0?pbearingf-tbearingf+360:pbearingf-tbearingf); 

    // min((a1-a2)<0?a1-a2+360:a1-a2, (a2-a1)<0?a2-a1+360:a2-a1)


     double aabearing=angle;

              float atot=apoint.distanceTo(tpoint);

     double atotdis=atot;

             //right angle triangle formula
     dis=(Math.sin(aabearing))*atotdis;

     return (dis);

}

现在两者仍然显示高达 30% 的大量错误。这段代码看起来是否正确,有没有更好的方法可以做到这一点,或者我的错误在哪里。我的 GPS 显示 4 米精度,而我的公式(代码)显示 10 到 20 米的误差,而且似乎不太一样。

【问题讨论】:

  • 你试过distanceTo()distanceBetween() Location类的方法吗......
  • @MichaelShrestha 我使用 distanceTo() 来获得从点 a 到(目标 ....*sin 角 = 点 a 的对边)的距离。直角三角形。 B 点仅提供一条线的方位角,三角形由目标与 a、b 线上的直角组成,如mathsisfun.com/algebra/trig-finding-side-right-triangle.html。我实际上不知道它与直线相交的位置,我只想知道到它的距离。

标签: android math haversine


【解决方案1】:

您可以使用 Google Geometry 库来查找线的长度及其方位。

来自文档

computeDistanceBetween(from:LatLng, to:LatLng, radius?:number) 返回 两个 LatLng 之间的距离,以米为单位。半径 默认为以米为单位的地球半径 (6378137)。

computeHeading(from:LatLng, to:LatLng) 从一开始返回航向 LatLng 到另一个 LatLng。标题以顺时针度数表示 从北在 [-180,180) 范围内作为数字。

computeOffset(from:LatLng, distance:number, heading:number, radius?:number) 返回移动距离产生的 La​​tLng 从指定航向的原点(以度数表示 从北顺时针)作为LatLng。

首先找到行首和行尾之间的距离

var spherical = google.maps.geometry.spherical; 
var length = google.maps.geometry.spherical.computeDistanceBetween(A,B);

然后找到线的方位

 var heading = google.maps.geometry.spherical.computeHeading(A,B);

从图像 120 度

然后求A线起点到C点的距离和方位

var length2 = google.maps.geometry.spherical.computeDistanceBetween(A,C);
var heading2 = google.maps.geometry.spherical.computeHeading(A,C);

距离图像 50 度

var angleBAC = heading1-heading2

角度 BAC = 120 - 50 度 = 70度

既然您现在知道角度 BAC 和从 A 到 C 的距离,您可以使用三角函数求长度 CD

sineBAC = opp/Hypotenuese

var CD = Math.sin(angleBAC) * length2;

来自图像

opp = 正弦 70 度 X 长度 AC

从图像 0.9397 X 5 = 4.6984

【讨论】:

  • 我仍然会遇到从 10 度到 -10 度的问题,而且我已经做了更多的测试,这让我感到悲痛,因为有时我的代码有效,但它却没有。你已经解释得更好了。
  • 是的,但我弄错了,我的代码中是 10 -350。添加了这个,但我认为需要进一步测试 if (bearingr>360){ Bearingr=bearingr-360; } if (bearingr360){bearingl=bearingl-360; } if (bearingl
  • Computeoffset 修复了该问题
  • 我的代码在大圆路线中给出了初始方位。它与其他应用程序要求不相关,并且随着初始方位的变化而给出不正确的答案。使用 rhumb line nav 或这个答案。
猜你喜欢
  • 1970-01-01
  • 2011-02-22
  • 2011-02-12
  • 1970-01-01
  • 1970-01-01
  • 2016-10-20
  • 1970-01-01
  • 2011-09-26
  • 1970-01-01
相关资源
最近更新 更多