Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
f108c687
Commit
f108c687
authored
Jun 29, 2015
by
antirez
Browse files
Geo: GEODIST and tests.
parent
a12192f5
Changes
6
Hide whitespace changes
Inline
Side-by-side
deps/geohash-int/geohash_helper.c
View file @
f108c687
...
@@ -167,7 +167,7 @@ GeoHashFix52Bits geohashAlign52Bits(const GeoHashBits hash) {
...
@@ -167,7 +167,7 @@ GeoHashFix52Bits geohashAlign52Bits(const GeoHashBits hash) {
}
}
/* Calculate distance using haversin great circle distance formula. */
/* Calculate distance using haversin great circle distance formula. */
double
d
istance
Earth
(
double
lon1d
,
double
lat1d
,
double
lon2d
,
double
lat2d
)
{
double
geohashGetD
istance
(
double
lon1d
,
double
lat1d
,
double
lon2d
,
double
lat2d
)
{
double
lat1r
,
lon1r
,
lat2r
,
lon2r
,
u
,
v
;
double
lat1r
,
lon1r
,
lat2r
,
lon2r
,
u
,
v
;
lat1r
=
deg_rad
(
lat1d
);
lat1r
=
deg_rad
(
lat1d
);
lon1r
=
deg_rad
(
lon1d
);
lon1r
=
deg_rad
(
lon1d
);
...
@@ -182,7 +182,7 @@ double distanceEarth(double lon1d, double lat1d, double lon2d, double lat2d) {
...
@@ -182,7 +182,7 @@ double distanceEarth(double lon1d, double lat1d, double lon2d, double lat2d) {
int
geohashGetDistanceIfInRadius
(
double
x1
,
double
y1
,
int
geohashGetDistanceIfInRadius
(
double
x1
,
double
y1
,
double
x2
,
double
y2
,
double
radius
,
double
x2
,
double
y2
,
double
radius
,
double
*
distance
)
{
double
*
distance
)
{
*
distance
=
d
istance
Earth
(
x1
,
y1
,
x2
,
y2
);
*
distance
=
geohashGetD
istance
(
x1
,
y1
,
x2
,
y2
);
if
(
*
distance
>
radius
)
return
0
;
if
(
*
distance
>
radius
)
return
0
;
return
1
;
return
1
;
}
}
...
...
deps/geohash-int/geohash_helper.h
View file @
f108c687
...
@@ -58,6 +58,8 @@ GeoHashRadius geohashGetAreasByRadiusWGS84(double longitude, double latitude,
...
@@ -58,6 +58,8 @@ GeoHashRadius geohashGetAreasByRadiusWGS84(double longitude, double latitude,
GeoHashRadius
geohashGetAreasByRadiusMercator
(
double
longitude
,
double
latitude
,
GeoHashRadius
geohashGetAreasByRadiusMercator
(
double
longitude
,
double
latitude
,
double
radius_meters
);
double
radius_meters
);
GeoHashFix52Bits
geohashAlign52Bits
(
const
GeoHashBits
hash
);
GeoHashFix52Bits
geohashAlign52Bits
(
const
GeoHashBits
hash
);
double
geohashGetDistance
(
double
lon1d
,
double
lat1d
,
double
lon2d
,
double
lat2d
);
int
geohashGetDistanceIfInRadius
(
double
x1
,
double
y1
,
int
geohashGetDistanceIfInRadius
(
double
x1
,
double
y1
,
double
x2
,
double
y2
,
double
radius
,
double
x2
,
double
y2
,
double
radius
,
double
*
distance
);
double
*
distance
);
...
...
src/geo.c
View file @
f108c687
...
@@ -112,6 +112,30 @@ static int longLatFromMember(robj *zobj, robj *member, double *xy) {
...
@@ -112,6 +112,30 @@ static int longLatFromMember(robj *zobj, robj *member, double *xy) {
return
REDIS_OK
;
return
REDIS_OK
;
}
}
/* Check that the unit argument matches one of the known units, and returns
* the conversion factor to meters (you need to divide meters by the conversion
* factor to convert to the right unit).
*
* If the unit is not valid, an error is reported to the client, and a value
* less than zero is returned. */
double
extractUnitOrReply
(
redisClient
*
c
,
robj
*
unit
)
{
char
*
u
=
unit
->
ptr
;
if
(
!
strcmp
(
u
,
"m"
)
||
!
strncmp
(
u
,
"meter"
,
5
))
{
return
1
;
}
else
if
(
!
strcmp
(
u
,
"ft"
)
||
!
strncmp
(
u
,
"feet"
,
4
))
{
return
0
.
3048
;
}
else
if
(
!
strcmp
(
u
,
"mi"
)
||
!
strncmp
(
u
,
"mile"
,
4
))
{
return
1609
.
34
;
}
else
if
(
!
strcmp
(
u
,
"km"
)
||
!
strncmp
(
u
,
"kilometer"
,
9
))
{
return
1000
;
}
else
{
addReplyError
(
c
,
"unsupported unit provided. please use meters (m), "
"kilometers (km), miles (mi), or feet (ft)"
);
return
-
1
;
}
}
/* Input Argument Helper.
/* Input Argument Helper.
* Extract the dinstance from the specified two arguments starting at 'argv'
* Extract the dinstance from the specified two arguments starting at 'argv'
* that shouldbe in the form: <number> <unit> and return the dinstance in the
* that shouldbe in the form: <number> <unit> and return the dinstance in the
...
@@ -127,25 +151,10 @@ static double extractDistanceOrReply(redisClient *c, robj **argv,
...
@@ -127,25 +151,10 @@ static double extractDistanceOrReply(redisClient *c, robj **argv,
return
-
1
;
return
-
1
;
}
}
double
to_meters
;
double
to_meters
=
extractUnitOrReply
(
c
,
argv
[
1
]);
sds
units
=
argv
[
1
]
->
ptr
;
if
(
to_meters
<
0
)
return
-
1
;
if
(
!
strcmp
(
units
,
"m"
)
||
!
strncmp
(
units
,
"meter"
,
5
))
{
to_meters
=
1
;
}
else
if
(
!
strcmp
(
units
,
"ft"
)
||
!
strncmp
(
units
,
"feet"
,
4
))
{
to_meters
=
0
.
3048
;
}
else
if
(
!
strcmp
(
units
,
"mi"
)
||
!
strncmp
(
units
,
"mile"
,
4
))
{
to_meters
=
1609
.
34
;
}
else
if
(
!
strcmp
(
units
,
"km"
)
||
!
strncmp
(
units
,
"kilometer"
,
9
))
{
to_meters
=
1000
;
}
else
{
addReplyError
(
c
,
"unsupported unit provided. please use meters (m), "
"kilometers (km), miles (mi), or feet (ft)"
);
return
-
1
;
}
if
(
conversion
)
*
conversion
=
to_meters
;
if
(
conversion
)
*
conversion
=
to_meters
;
return
distance
*
to_meters
;
return
distance
*
to_meters
;
}
}
...
@@ -742,3 +751,42 @@ void geoposCommand(redisClient *c) {
...
@@ -742,3 +751,42 @@ void geoposCommand(redisClient *c) {
}
}
}
}
}
}
/* GEODIST key ele1 ele2 [unit]
*
* Return the distance, in meters by default, otherwise accordig to "unit",
* between points ele1 and ele2. If one or more elements are missing NULL
* is returned. */
void
geodistCommand
(
redisClient
*
c
)
{
double
to_meter
=
1
;
/* Check if there is the unit to extract, otherwise assume meters. */
if
(
c
->
argc
==
5
)
{
to_meter
=
extractUnitOrReply
(
c
,
c
->
argv
[
4
]);
if
(
to_meter
<
0
)
return
;
}
else
if
(
c
->
argc
>
5
)
{
addReply
(
c
,
shared
.
syntaxerr
);
return
;
}
/* Look up the requested zset */
robj
*
zobj
=
NULL
;
if
((
zobj
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
emptybulk
))
==
NULL
||
checkType
(
c
,
zobj
,
REDIS_ZSET
))
return
;
/* Get the scores. We need both otherwise NULL is returned. */
double
score1
,
score2
,
xyxy
[
4
];
if
(
zsetScore
(
zobj
,
c
->
argv
[
2
],
&
score1
)
==
REDIS_ERR
||
zsetScore
(
zobj
,
c
->
argv
[
3
],
&
score2
)
==
REDIS_ERR
)
{
addReply
(
c
,
shared
.
nullbulk
);
return
;
}
/* Decode & compute the distance. */
if
(
!
decodeGeohash
(
score1
,
xyxy
)
||
!
decodeGeohash
(
score2
,
xyxy
+
2
))
addReply
(
c
,
shared
.
nullbulk
);
else
addReplyDouble
(
c
,
geohashGetDistance
(
xyxy
[
0
],
xyxy
[
1
],
xyxy
[
2
],
xyxy
[
3
])
/
to_meter
);
}
src/redis.c
View file @
f108c687
...
@@ -289,6 +289,7 @@ struct redisCommand redisCommandTable[] = {
...
@@ -289,6 +289,7 @@ struct redisCommand redisCommandTable[] = {
{
"geodecode"
,
geodecodeCommand
,
2
,
"r"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"geodecode"
,
geodecodeCommand
,
2
,
"r"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"geohash"
,
geohashCommand
,
-
2
,
"r"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"geohash"
,
geohashCommand
,
-
2
,
"r"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"geopos"
,
geoposCommand
,
-
2
,
"r"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"geopos"
,
geoposCommand
,
-
2
,
"r"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"geodist"
,
geodistCommand
,
-
4
,
"r"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"pfselftest"
,
pfselftestCommand
,
1
,
"r"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"pfselftest"
,
pfselftestCommand
,
1
,
"r"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"pfadd"
,
pfaddCommand
,
-
2
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"pfadd"
,
pfaddCommand
,
-
2
,
"wmF"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"pfcount"
,
pfcountCommand
,
-
2
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"pfcount"
,
pfcountCommand
,
-
2
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
...
...
src/redis.h
View file @
f108c687
...
@@ -1565,6 +1565,7 @@ void georadiusCommand(redisClient *c);
...
@@ -1565,6 +1565,7 @@ void georadiusCommand(redisClient *c);
void
geoaddCommand
(
redisClient
*
c
);
void
geoaddCommand
(
redisClient
*
c
);
void
geohashCommand
(
redisClient
*
c
);
void
geohashCommand
(
redisClient
*
c
);
void
geoposCommand
(
redisClient
*
c
);
void
geoposCommand
(
redisClient
*
c
);
void
geodistCommand
(
redisClient
*
c
);
void
pfselftestCommand
(
redisClient
*
c
);
void
pfselftestCommand
(
redisClient
*
c
);
void
pfaddCommand
(
redisClient
*
c
);
void
pfaddCommand
(
redisClient
*
c
);
void
pfcountCommand
(
redisClient
*
c
);
void
pfcountCommand
(
redisClient
*
c
);
...
...
tests/unit/geo.tcl
View file @
f108c687
...
@@ -109,6 +109,28 @@ start_server {tags {"geo"}} {
...
@@ -109,6 +109,28 @@ start_server {tags {"geo"}} {
lindex
[
r geopos points a x b
]
1
lindex
[
r geopos points a x b
]
1
}
{}
}
{}
test
{
GEODIST simple & unit
}
{
r del points
r geoadd points 13.361389 38.115556
"Palermo"
\
15.087269 37.502669
"Catania"
set m
[
r geodist points Palermo Catania
]
assert
{
$m
> 166274 && $m < 166275
}
set km
[
r geodist points Palermo Catania km
]
assert
{
$km
> 166.2 && $km < 166.3
}
}
test
{
GEODIST missing elements
}
{
r del points
r geoadd points 13.361389 38.115556
"Palermo"
\
15.087269 37.502669
"Catania"
set m
[
r geodist points Palermo Agrigento
]
assert
{
$m
eq
{}}
set m
[
r geodist points Ragusa Agrigento
]
assert
{
$m
eq
{}}
set m
[
r geodist empty_key Palermo Catania
]
assert
{
$m
eq
{}}
}
test
{
GEOADD + GEORANGE randomized test
}
{
test
{
GEOADD + GEORANGE randomized test
}
{
set attempt 10
set attempt 10
while
{[
incr attempt -1
]}
{
while
{[
incr attempt -1
]}
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment