uint64_t geohash64(double longitude, double latitude) { if ((fabs(longitude) > 180.0) || (fabs(latitude) > 90.0)) return 0; GeoHashBits h; geohashEncodeWGS84(longitude, latitude, GEO_STEP_MAX, &h); return geohashAlign52Bits(h); }
uint64_t geohash_decode64(char* buf) { double coords[2][2] = { { -90.0, 90.0 }, { -180.0, 180.0 } }; int bits[] = { 16, 8, 4, 2, 1 }; int flip = 1; for (int i = 0; i < 11; i++) { char* pch = strchr(geoalphabet, buf[i]); if (pch == NULL) return 0; int pos = pch - geoalphabet; for (int j = 0; j < 5; j++) { coords[flip][((pos & bits[j]) > 0) ? 0 : 1] = (coords[flip][0] + coords[flip][1]) / 2.0; flip = !flip; } } GeoHashBits hash; geohashEncodeWGS84(*coords[1,1], *coords[1,0], GEO_STEP_MAX, &hash); return geohashAlign52Bits(hash); }
bool ssdb_geo_set( SSDBSock *ssdb_sock, char *key, int key_len, char *member_key, int member_key_len, double latitude, double longitude, INTERNAL_FUNCTION_PARAMETERS) { GeoHashBits hash; if (!geohashEncodeWGS84(latitude, longitude, GEO_STEP_MAX, &hash)) { return false; } char *member_score_str = NULL, *cmd = NULL; GeoHashFix52Bits bits = geohashAlign52Bits(hash); int member_score_str_len = spprintf(&member_score_str, 0, "%lld", bits); int key_free = ssdb_key_prefix(ssdb_sock, &key, &key_len); int cmd_len = ssdb_cmd_format_by_str(ssdb_sock, &cmd, ZEND_STRL("zset"), key, key_len, member_key, member_key_len, member_score_str, member_score_str_len, NULL); efree(member_score_str); if (key_free) efree(key); if (0 == cmd_len) return false; if (ssdb_sock_write(ssdb_sock, cmd, cmd_len) < 0) { efree(cmd); return false; } efree(cmd); SSDBResponse *ssdb_response = ssdb_sock_read(ssdb_sock); if (ssdb_response == NULL || ssdb_response->status != SSDB_IS_OK) { ssdb_response_free(ssdb_response); return false; } ssdb_response_free(ssdb_response); RETVAL_LONG(bits); return true; }
static SSDBGeoList *ssdb_geo_member_box(SSDBGeoObj *ssdb_geo_obj, GeoHashBits hash) { GeoHashFix52Bits min, max; min = geohashAlign52Bits(hash); hash.bits++; max = geohashAlign52Bits(hash); char *score_start = NULL; int score_start_len = spprintf(&score_start, 0, "%lld", min); char *score_end = NULL; int score_end_len = spprintf(&score_end, 0, "%lld", max); char *cmd = NULL; int cmd_len = 0, key_free = 0; key_free = ssdb_key_prefix(ssdb_geo_obj->ssdb_sock, &ssdb_geo_obj->key, &ssdb_geo_obj->key_len); cmd_len = ssdb_cmd_format_by_str(ssdb_geo_obj->ssdb_sock, &cmd, ZEND_STRL("zscan"), ssdb_geo_obj->key, ssdb_geo_obj->key_len, "", 0, score_start, score_start_len, score_end, score_end_len, ssdb_geo_obj->limit_str, ssdb_geo_obj->limit_str_len, NULL); efree(score_start); efree(score_end); if (key_free) efree(ssdb_geo_obj->key); if (0 == cmd_len) return NULL; if (ssdb_sock_write(ssdb_geo_obj->ssdb_sock, cmd, cmd_len) < 0) { efree(cmd); return NULL; } efree(cmd); SSDBResponse *ssdb_response = ssdb_sock_read(ssdb_geo_obj->ssdb_sock); if (ssdb_response == NULL || ssdb_response->status != SSDB_IS_OK || ssdb_response->num % 2 != 0) { ssdb_response_free(ssdb_response); return NULL; } //创建链表 SSDBGeoList *l = ssdb_geo_list_create(); if (l == NULL) { return NULL; } l->free = free; double latlong[2] = {0}; int i = 1; bool err = false; SSDBResponseBlock *ssdb_response_block = ssdb_response->block; while (ssdb_response_block != NULL) { if (0 == i % 2) { if (!decodeGeohash(atoll(ssdb_response_block->data), latlong)) { err = true; break; } SSDBGeoPoint *p = malloc(sizeof (SSDBGeoPoint)); p->member_key_len = ssdb_response_block->prev->len; p->member = estrndup(ssdb_response_block->prev->data, ssdb_response_block->prev->len); p->dist = 0.0; p->latitude = latlong[0]; p->longitude = latlong[1]; ssdb_geo_list_add_tail_node(l, p); } ssdb_response_block = ssdb_response_block->next; i++; } if (err || 0 == l->num) { ssdb_geo_list_destory(l); l = NULL; } ssdb_response_free(ssdb_response); return l; }