Как найти географическую точку между двумя другими точками - PullRequest
2 голосов
/ 06 октября 2011

Для моего приложения я должен найти положение точки на карте Google, зная только то, что она расположена между 2 другими точками и временем (в мс), когда координаты были получены.

В моем коде, предполагая A и B в качестве заданных точек и X в качестве точки, которую нужно найти, I:

  1. вычислить расстояние между A и B

  2. базированиевовремя я узнал скорость (в микро градусах / мс), чтобы пройти путь от А до В

  3. Я нашел расстояние от точки А и точки X (используя время и скорость)

  4. используя аналогичное правило треугольника, я вычисляю широту и долготу точки X из точки A

Этот рабочий процесс выявляет ошибки на карте, поэтому частомаркер X не находится на линии между маркерами A и B.

Как я могу заставить его работать лучше?Это проблема сферичности земного шара?

Спасибо всем.

Вот код:

    int ax = oldPoint.getLatitude();
    int ay = oldPoint.getLongitude();

    int bx = currentPoint.getLatitude();
    int by = currentPoint.getLongitude();

    long at = oldPoint.getDataRilevamento(); //get time first point
    long bt = currentPoint.getDataRilevamento(); // get time second point
    long xt = x.getDate(); // time of point to find

    int c1 = bx-ax;
    int c2 = by-ay;
    double hyp =  Math.sqrt(Math.pow(c1, 2) + Math.pow(c2, 2));

    double vel = hyp / (bt-at);

    double pos = vel*(xt - at);

    int posx = (int)((pos*c1)/hyp);
    int posy = (int)((pos*c2)/hyp);

    x.setLatitude(ax+posx); //set the latitude of X
    x.setLongitude(ay+posy); // set the longitude of X

1 Ответ

14 голосов
/ 06 октября 2011

Ваша проблема может быть решена с помощью следующих шагов:

  • Рассчитайте расстояние от точек A и B (используйте формулу Haversine , которая достаточно хорошаздесь, или более сложная формула Винсенти ).Чтобы правильно использовать формулу, микродегиды Android, которые возвращают getLatitude и getLongitude, необходимо преобразовать в радианы, используя следующую формулу:

     double radians = Math.toRadians((double)microdegrees/1000000);
    
  • Рассчитать направление (направление)из точек А и В (используйте формулу на той же странице).Это будет отличаться от формулы Пифагора, потому что земля круглая, а не плоская.

  • Затем вы можете выбрать новое расстояние и рассчитать точку X для данной точки A и опоры, найденной на предыдущем шаге (см.либо «Точка назначения с указанным расстоянием и азимутом от начальной точки» на той же странице, либо прямая формула Винсенти ).
  • Преобразуйте радианы из сгенерированной точки в микродепуты, используя эту формулу:

     int microdegrees = (int)(Math.toDegrees(radians)*1000000);
    

Собрав все это вместе, мы имеем следующую функцию, которую я помещаю в общественное достояние:

    public static int[] getIntermediatePoint(
        int startLatMicroDeg,
        int startLonMicroDeg,
        int endLatMicroDeg,
        int endLonMicroDeg,
        double t // How much of the distance to use, from 0 through 1
    ){
        // Convert microdegrees to radians
        double alatRad=Math.toRadians((double)startLatMicroDeg/1000000);
        double alonRad=Math.toRadians((double)startLonMicroDeg/1000000);
        double blatRad=Math.toRadians((double)endLatMicroDeg/1000000);
        double blonRad=Math.toRadians((double)endLonMicroDeg/1000000);
        // Calculate distance in longitude
        double dlon=blonRad-alonRad;
        // Calculate common variables
        double alatRadSin=Math.sin(alatRad);
        double blatRadSin=Math.sin(blatRad);
        double alatRadCos=Math.cos(alatRad);
        double blatRadCos=Math.cos(blatRad);
        double dlonCos=Math.cos(dlon);
        // Find distance from A to B
        double distance=Math.acos(alatRadSin*blatRadSin +
                                  alatRadCos*blatRadCos *
                                  dlonCos);
        // Find bearing from A to B
        double bearing=Math.atan2(
            Math.sin(dlon) * blatRadCos,
            alatRadCos*blatRadSin -
            alatRadSin*blatRadCos*dlonCos);
        // Find new point
        double angularDistance=distance*t;
        double angDistSin=Math.sin(angularDistance);
        double angDistCos=Math.cos(angularDistance);
        double xlatRad = Math.asin( alatRadSin*angDistCos +
                                   alatRadCos*angDistSin*Math.cos(bearing) );
        double xlonRad = alonRad + Math.atan2(
            Math.sin(bearing)*angDistSin*alatRadCos,
            angDistCos-alatRadSin*Math.sin(xlatRad));
        // Convert radians to microdegrees
        int xlat=(int)Math.round(Math.toDegrees(xlatRad)*1000000);
        int xlon=(int)Math.round(Math.toDegrees(xlonRad)*1000000);
        if(xlat>90000000)xlat=90000000;
        if(xlat<-90000000)xlat=-90000000;
        while(xlon>180000000)xlon-=360000000;
        while(xlon<=-180000000)xlon+=360000000;
        return new int[]{xlat,xlon};
    }

И вот как она используется:

int ax = oldPoint.getLatitude();
int ay = oldPoint.getLongitude();

int bx = currentPoint.getLatitude();
int by = currentPoint.getLongitude();

long at = oldPoint.getDataRilevamento(); //get time first point
long bt = currentPoint.getDataRilevamento(); // get time second point
long xt = x.getDate(); // time of point to find

// Find relative time from point A to point B
double t=(bt==at) ? 0 : ((double)(xt-at))/((double)(bt-at));
// Find new point given the start and end points and the relative time
int[] xpos=getIntermediatePoint(ax,ay,bx,by,t);
x.setLatitude(xpos[0]); //set the latitude of X
x.setLongitude(xpos[1]); // set the longitude of X
...