Есть ли простой способ сделать грубые координаты GPS? - PullRequest
2 голосов
/ 05 ноября 2011

Я работаю над приложением для iPhone, которое использует GPS-координаты для списков лидеров. Мне не нужны точные координаты - на самом деле я никогда не хочу точные координаты, чтобы защитить конфиденциальность пользователя.

Я указываю kCLLocationAccuracyThreeKilmeters для желаемой точности, но когда GPS активен, кажется, что он также может подобрать точное местоположение, когда устройство имеет его.

ВОПРОС: Можно ли использовать какой-нибудь простой алгоритм, чтобы сделать данные GPS более грубыми? Скажи, сделай это гранулированным до 3км.

Если я просто увеличу числа, уберу десятичные точки и снова уменьшу их, это сделает его более грубым в некоторых частях мира, чем в других.

Спасибо!

Ответы [ 4 ]

3 голосов
/ 13 ноября 2011

Хотя ответ Марка, приведенный выше, был полезен, он все равно не дал формулы с непротиворечивыми результатами, поскольку он опирался на генератор случайных чисел.

Мой друг дал лучший ответ на этот вопрос:

Вокруг лат, lon, до ближайшего значимого числа в зависимости от степени детализации, но это приведет к тому, что все широты / lon вблизи определенного местоположения окажутся в одном и том же месте. Этот метод будет использовать расстояние между двумя точками в широте / долготе для вычисления округления широты. Используйте ту же формулу ниже и установите курс на 0, тогда расстояние - это ваша гранулярность расстояния. Рассчитайте полученный новый лат / долг, вычтите два лат / лон, чтобы получить сумму округления для лат. Затем установите заголовок равным 90, пересчитайте и вычтите новый лат / лон из старого, чтобы получить сумму округления для лона.

А вот код C ++:

class LocationUtility
{
  public: static Location getLocationNow()
  {
    Location location;

    if(context != null)
    {
      double latitude = 0;
      double longitude = 0;
      ::of_getCurrentLocation(&latitude, &longitude);

      location.setLatitude(latitude);
      location.setLongitude(longitude);

      location = makeLocationCoarse(location);
    }

    return location;
  }

  public: static Location makeLocationCoarse(const Location& location)
  {
      double granularityInMeters = 3 * 1000;
      return makeLocationCoarse(location, granularityInMeters);
  }

  public: static Location makeLocationCoarse(const Location& location,
             double granularityInMeters)
  {
    Location courseLocation;

    if(location.getLatitude() == (double)0 && 
      location.getLongitude() == (double)0)
    {
      // Special marker, don't bother.
    }
    else
    {
      double granularityLat = 0;
      double granularityLon = 0;
      {
        // Calculate granularityLat
        {
          double angleUpInRadians = 0;
          Location newLocationUp = getLocationOffsetBy(location, 
            granularityInMeters, angleUpInRadians);

          granularityLat = location.getLatitude() - 
            newLocationUp.getLatitude();

          if(granularityLat < (double)0)
          {
            granularityLat = -granularityLat;
          }
        }

        // Calculate granularityLon
        {
          double angleRightInRadians = 1.57079633;
          Location newLocationRight = getLocationOffsetBy(location,
            granularityInMeters, angleRightInRadians);

          granularityLon = location.getLongitude() - 
            newLocationRight.getLongitude();

          if(granularityLon < (double)0)
          {
            granularityLon = -granularityLon;
          }
        }
      }

      double courseLatitude = location.getLatitude();
      double courseLongitude = location.getLongitude();
      {
        if(granularityLon == (double)0 || granularityLat == (double)0)
        {
          courseLatitude = 0;
          courseLongitude = 0;
        }
        else
        {
          courseLatitude = (int)(courseLatitude / granularityLat) * 
            granularityLat;

          courseLongitude = (int)(courseLongitude / granularityLon) * 
            granularityLon;
        }
      }
      courseLocation.setLatitude(courseLatitude);
      courseLocation.setLongitude(courseLongitude);
    }

    return courseLocation;
  }

  // http://www.movable-type.co.uk/scripts/latlong.html
  private: static Location getLocationOffsetBy(const Location& location,
    double offsetInMeters, double angleInRadians)
  {
    Location newLocation;

    double lat1 = location.getLatitude();
    double lon1 = location.getLongitude();

    lat1 = deg2rad(lat1);
    lon1 = deg2rad(lon1);

    double distanceKm = offsetInMeters / (double)1000;
    const double earthRadiusKm = 6371;

    double lat2 = asin( sin(lat1)*cos(distanceKm/earthRadiusKm) + 
      cos(lat1)*sin(distanceKm/earthRadiusKm)*cos(angleInRadians) );

    double lon2 = lon1 + 
      atan2(sin(angleInRadians)*sin(distanceKm/earthRadiusKm)*cos(lat1), 
      cos(distanceKm/earthRadiusKm)-sin(lat1)*sin(lat2));

    lat2 = rad2deg(lat2);
    lon2 = rad2deg(lon2);

    newLocation.setLatitude(lat2);
    newLocation.setLongitude(lon2);

    return newLocation;
  }

  private: static double rad2deg(double radians)
  {
    static double ratio = (double)(180.0 / 3.141592653589793238);
    return radians * ratio;
  }

  private: static double deg2rad(double radians)
  {
    static double ratio = (double)(180.0 / 3.141592653589793238);
    return radians / ratio;
  }

  /*
  public: static void testCoarse()
  {
    Location vancouver(49.2445, -123.099146);
    Location vancouver2 = makeLocationCoarse(vancouver);

    Location korea(37.423938, 126.692488);
    Location korea2 = makeLocationCoarse(korea);

    Location hiroshima(34.3937, 132.464);
    Location hiroshima2 = makeLocationCoarse(hiroshima);

    Location zagreb(45.791958, 15.935786);
    Location zagreb2 = makeLocationCoarse(zagreb);

    Location anchorage(61.367778, -149.900208);
    Location anchorage2 = makeLocationCoarse(anchorage);
  }*/
};
2 голосов
/ 09 ноября 2011

Это очень похоже на предыдущий вопрос Округление по широте и длине, чтобы показать приблизительное местоположение в Google Maps

Если вы предполагаете, что Земля является сферой (вероятно, адекватной для этой проблемы),тогда вам просто нужно рассчитать местоположение, которое является определенным угловым расстоянием от заданной широты и долготы.Выберите расстояние и (случайное) направление и рассчитайте новое местоположение, используя формулу расстояния.

Здесь хорошо обсуждается противоположная проблема (расстояние между двумя точками широты / долготы): http://mathforum.org/library/drmath/view/51756.html

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

1 голос
/ 24 мая 2018

Ответ от swinefeaster в порядке, но в такой сложной математике нет необходимости.Если вы округляетесь до сетки, то широта изменяется на постоянную величину во всех точках планеты.Долгота изменяется на разные величины в зависимости от того, как далеко вы находитесь от экватора.

Следующий код привязывает широту и долготу к произвольному размеру сетки

double EARTH_RADIUS_KM = 6371;

double GRID_SIZE_KM = 1.6; // <----- Our grid size in km..

double DEGREES_LAT_GRID = Math.toDegrees(GRID_SIZE_KM / EARTH_RADIUS_KM);
//     ^^^^^^ This is constant for a given grid size.

public Location snapToGrid(Location myLoc) {
  double cos = Math.cos(Math.toRadians(myLoc.latitude));

  double degreesLonGrid = DEGREES_LAT_GRID / cos;

  return new Location (
      Math.round(myLoc.longitude / degreesLonGrid) * degreesLonGrid,
      Math.round(myLoc.latitude / DEGREES_LAT_GRID) * DEGREES_LAT_GRID);

}

Обратите внимание, что в этом случае произойдет ошибкагде вы находитесь на полюсе (когда функция cos приближается к нулю).В зависимости от размера вашей сетки результаты становятся непредсказуемыми, когда вы приближаетесь к широте +/- 90 градусов.Обработка этого упражнения оставлена ​​читателю:)

0 голосов
/ 11 января 2017

Я пытаюсь реализовать решение в Ruby, но в моем случае грубая координата и действительная имеют огромную разницу. грубая координата изменяется только при изменении широты, но когда широта остается неизменной, а при длинном движении грубая остается неизменной. В случае, если кто-то может проверить код ниже, возможно, я сделал плохое кодирование.

class CoarseLocation

  AREA_LIMIT = 1000

  class << self

    def make_location_coarse(lat, lon)

      if lat.nil? && lon.nil?
        raise InvalidParamsError
      end

      location = [lat.to_f, lat.to_f]

      new_location_up =  get_location_by_offset(location, AREA_LIMIT, 0)

      granularityLat = location[0] - new_location_up[0]

      if granularityLat < 0
        granularityLat = -granularityLat
      end


      new_location_right = get_location_by_offset(location, AREA_LIMIT, 1.57079633)

      granularityLon = location[1] - new_location_right[1]

      if(granularityLon < 0)
        granularityLon = -granularityLon
      end

      course_lat = location[0]
      course_lon = location[1]

      if(granularityLat ==  0.0) || (granularityLon == 0.0)
        course_lat = 0
        course_lon = 0
      else
        course_lat = (course_lat / granularityLat).to_i * granularityLat
        course_lon = (course_lon / granularityLon).to_i * granularityLon
      end

      [course_lat, course_lon]
    end

    def get_location_by_offset(location, offset, angle)
      lat_radius = location[0] * Math::PI / 180
      lon_radius = location[1] * Math::PI / 180

      distance = (offset / 1000).to_f
      earth_radius = 6371

      lat_radius_1 = (Math::asin( Math::sin(lat_radius) * Math::cos(distance/earth_radius) + Math::cos(lat_radius) * Math::sin(distance/earth_radius) * Math::cos(angle))).to_f
      lon_radius_1 = (lon_radius + Math::atan2(Math::sin(angle)*Math::sin(distance/earth_radius)*Math::cos(lat_radius), Math::cos(distance/earth_radius) - Math::sin(lat_radius)*Math::sin(lat_radius_1))).to_f

      new_lat = lat_radius_1 * 180 / Math::PI
      new_lon = lon_radius_1 * 180 / Math::PI

      return [new_lat.to_f, new_lon.to_f]

    end
  end
end

Поле местоположения всегда представляет собой массив из 2 элементов, в котором [0] является широтой, а [1] длинным.

...