有没有简单的方法使GPS坐标粗糙?

时间:2011-11-05 07:20:11

标签: geolocation

我正在开发一款使用GPS坐标进行排行榜的iPhone应用。我不需要坐标准确 - 实际上我并不希望坐标准确,以保护用户隐私。

我正在为期望的准确度指定kCLLocationAccuracyThreeKilometers,但是当GPS处于活动状态时,它似乎也可以在设备拥有它时获取确切的位置。

问题:我可以使用任何简单的算法来使GPS数据更粗糙吗?比如说,让它精细到3km。

如果我只是缩放数字并删除小数点并再次缩小它会使它在世界某些地方比其他地方更粗糙。

谢谢!

3 个答案:

答案 0 :(得分:2)

这与之前的问题非常相似 Rounding Lat and Long to Show Approximate Location in Google Maps

如果你假设地球是一个球体(可能适合这个问题),那么你只需要计算一个与给定纬度和经度有一定距离的位置。选择距离和(随机)方向,并使用距离公式计算新位置。

这里有相反问题(两个纬度/经度点之间的距离)的良好讨论:http://mathforum.org/library/drmath/view/51756.html

从那里去寻找距离给定点一定距离的点应该是相对简单的。

答案 1 :(得分:0)

我尝试在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]为lat且[1]为long。

答案 2 :(得分:0)

猪瘟的答案还可以,但不需要这么复杂的数学。如果您要四舍五入到网格,那么纬度会在地球上的所有点上以恒定量变化。根据你离赤道的距离,经度会有不同的变化。

以下代码将纬度和经度捕捉到任意网格大小

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度的纬度时,结果将变得不可预测。处理这是一个留给读者的练习:)