关键词搜索

源码搜索 ×
×

漫话Redis源码之五十九

发布2022-01-09浏览446次

详情内容

这里主要是计算区域,覆盖范围查询。

  1. /* Calculate a set of areas (center + 8) that are able to cover a range query
  2. * for the specified position and shape (see geohash.h GeoShape).
  3. * the bounding box saved in shaple.bounds */
  4. GeoHashRadius geohashCalculateAreasByShapeWGS84(GeoShape *shape) {
  5. GeoHashRange long_range, lat_range;
  6. GeoHashRadius radius;
  7. GeoHashBits hash;
  8. GeoHashNeighbors neighbors;
  9. GeoHashArea area;
  10. double min_lon, max_lon, min_lat, max_lat;
  11. int steps;
  12. geohashBoundingBox(shape, shape->bounds);
  13. min_lon = shape->bounds[0];
  14. min_lat = shape->bounds[1];
  15. max_lon = shape->bounds[2];
  16. max_lat = shape->bounds[3];
  17. double longitude = shape->xy[0];
  18. double latitude = shape->xy[1];
  19. /* radius_meters is calculated differently in different search types:
  20. * 1) CIRCULAR_TYPE, just use radius.
  21. * 2) RECTANGLE_TYPE, we use sqrt((widthhttps://files.jxasp.com/image/2)^2 + (heighthttps://files.jxasp.com/image/2)^2) to
  22. * calculate the distance from the center point to the corner */
  23. double radius_meters = shape->type == CIRCULAR_TYPE ? shape->t.radius :
  24. sqrt((shape->t.r.width/2)*(shape->t.r.width/2) + (shape->t.r.height/2)*(shape->t.r.height/2));
  25. radius_meters *= shape->conversion;
  26. steps = geohashEstimateStepsByRadius(radius_meters,latitude);
  27. geohashGetCoordRange(&long_range,&lat_range);
  28. geohashEncode(&long_range,&lat_range,longitude,latitude,steps,&hash);
  29. geohashNeighbors(&hash,&neighbors);
  30. geohashDecode(long_range,lat_range,hash,&area);
  31. /* Check if the step is enough at the limits of the covered area.
  32. * Sometimes when the search area is near an edge of the
  33. * area, the estimated step is not small enough, since one of the
  34. * north / south / west / east square is too near to the search area
  35. * to cover everything. */
  36. int decrease_step = 0;
  37. {
  38. GeoHashArea north, south, east, west;
  39. geohashDecode(long_range, lat_range, neighbors.north, &north);
  40. geohashDecode(long_range, lat_range, neighbors.south, &south);
  41. geohashDecode(long_range, lat_range, neighbors.east, &east);
  42. geohashDecode(long_range, lat_range, neighbors.west, &west);
  43. if (geohashGetDistance(longitude,latitude,longitude,north.latitude.max)
  44. < radius_meters) decrease_step = 1;
  45. if (geohashGetDistance(longitude,latitude,longitude,south.latitude.min)
  46. < radius_meters) decrease_step = 1;
  47. if (geohashGetDistance(longitude,latitude,east.longitude.max,latitude)
  48. < radius_meters) decrease_step = 1;
  49. if (geohashGetDistance(longitude,latitude,west.longitude.min,latitude)
  50. < radius_meters) decrease_step = 1;
  51. }
  52. if (steps > 1 && decrease_step) {
  53. steps--;
  54. geohashEncode(&long_range,&lat_range,longitude,latitude,steps,&hash);
  55. geohashNeighbors(&hash,&neighbors);
  56. geohashDecode(long_range,lat_range,hash,&area);
  57. }
  58. /* Exclude the search areas that are useless. */
  59. if (steps >= 2) {
  60. if (area.latitude.min < min_lat) {
  61. GZERO(neighbors.south);
  62. GZERO(neighbors.south_west);
  63. GZERO(neighbors.south_east);
  64. }
  65. if (area.latitude.max > max_lat) {
  66. GZERO(neighbors.north);
  67. GZERO(neighbors.north_east);
  68. GZERO(neighbors.north_west);
  69. }
  70. if (area.longitude.min < min_lon) {
  71. GZERO(neighbors.west);
  72. GZERO(neighbors.south_west);
  73. GZERO(neighbors.north_west);
  74. }
  75. if (area.longitude.max > max_lon) {
  76. GZERO(neighbors.east);
  77. GZERO(neighbors.south_east);
  78. GZERO(neighbors.north_east);
  79. }
  80. }
  81. radius.hash = hash;
  82. radius.neighbors = neighbors;
  83. radius.area = area;
  84. return radius;
  85. }
  86. GeoHashFix52Bits geohashAlign52Bits(const GeoHashBits hash) {
  87. uint64_t bits = hash.bits;
  88. bits <<= (52 - hash.step * 2);
  89. return bits;
  90. }
  91. /* Calculate distance using haversin great circle distance formula. */
  92. double geohashGetDistance(double lon1d, double lat1d, double lon2d, double lat2d) {
  93. double lat1r, lon1r, lat2r, lon2r, u, v;
  94. lat1r = deg_rad(lat1d);
  95. lon1r = deg_rad(lon1d);
  96. lat2r = deg_rad(lat2d);
  97. lon2r = deg_rad(lon2d);
  98. u = sin((lat2r - lat1r) / 2);
  99. v = sin((lon2r - lon1r) / 2);
  100. return 2.0 * EARTH_RADIUS_IN_METERS *
  101. asin(sqrt(u * u + cos(lat1r) * cos(lat2r) * v * v));
  102. }
  103. int geohashGetDistanceIfInRadius(double x1, double y1,
  104. double x2, double y2, double radius,
  105. double *distance) {
  106. *distance = geohashGetDistance(x1, y1, x2, y2);
  107. if (*distance > radius) return 0;
  108. return 1;
  109. }
  110. int geohashGetDistanceIfInRadiusWGS84(double x1, double y1, double x2,
  111. double y2, double radius,
  112. double *distance) {
  113. return geohashGetDistanceIfInRadius(x1, y1, x2, y2, radius, distance);
  114. }
  115. /* Judge whether a point is in the axis-aligned rectangle, when the distance
  116. * between a searched point and the center point is less than or equal to
  117. * heighthttps://files.jxasp.com/image/2 or widthhttps://files.jxasp.com/image/2 in height and width, the point is in the rectangle.
  118. *
  119. * width_m, height_m: the rectangle
  120. * x1, y1 : the center of the box
  121. * x2, y2 : the point to be searched
  122. */
  123. int geohashGetDistanceIfInRectangle(double width_m, double height_m, double x1, double y1,
  124. double x2, double y2, double *distance) {
  125. double lon_distance = geohashGetDistance(x2, y2, x1, y2);
  126. double lat_distance = geohashGetDistance(x2, y2, x2, y1);
  127. if (lon_distance > width_m/2 || lat_distance > height_m/2) {
  128. return 0;
  129. }
  130. *distance = geohashGetDistance(x1, y1, x2, y2);
  131. return 1;
  132. }

相关技术文章

点击QQ咨询
开通会员
返回顶部
×
微信扫码支付
微信扫码支付
确定支付下载
请使用微信描二维码支付
×

提示信息

×

选择支付方式

  • 微信支付
  • 支付宝付款
确定支付下载