null+****@clear*****
null+****@clear*****
2011年 12月 28日 (水) 15:46:47 JST
Kouhei Sutou 2011-12-28 15:46:47 +0900 (Wed, 28 Dec 2011)
New Revision: bfcc1ad209db71a72cecedc0f7aa2afe803e76d6
Log:
[geo] geo_in_circle() without index supports approximate type.
fixes #1226
Modified files:
lib/geo.c
lib/geo.h
lib/proc.c
test/unit/core/test-command-select-geo.c
test/unit/core/test-geo.c
Modified: lib/geo.c (+56 -32)
===================================================================
--- lib/geo.c 2011-12-28 15:19:27 +0900 (27c96c7)
+++ lib/geo.c 2011-12-28 15:46:47 +0900 (0f05b13)
@@ -701,6 +701,34 @@ grn_selector_geo_in_circle(grn_ctx *ctx, grn_obj *obj, grn_obj **args, int nargs
return ctx->rc;
}
+static grn_geo_distance_raw_func
+grn_geo_resolve_distance_raw_func (grn_ctx *ctx,
+ grn_geo_approximate_type approximate_type,
+ grn_id domain)
+{
+ grn_geo_distance_raw_func distance_raw_func = NULL;
+
+ switch (approximate_type) {
+ case GRN_GEO_APPROXIMATE_RECTANGLE :
+ distance_raw_func = grn_geo_distance_rectangle_raw;
+ break;
+ case GRN_GEO_APPROXIMATE_SPHERE :
+ distance_raw_func = grn_geo_distance_sphere_raw;
+ break;
+ case GRN_GEO_APPROXIMATE_ELLIPSOID :
+ if (domain == GRN_DB_WGS84_GEO_POINT) {
+ distance_raw_func = grn_geo_distance_ellipsoid_raw_wgs84;
+ } else {
+ distance_raw_func = grn_geo_distance_ellipsoid_raw_tokyo;
+ }
+ break;
+ default :
+ break;
+ }
+
+ return distance_raw_func;
+}
+
grn_rc
grn_geo_select_in_circle(grn_ctx *ctx, grn_obj *index,
grn_obj *center_point, grn_obj *distance,
@@ -743,25 +771,13 @@ grn_geo_select_in_circle(grn_ctx *ctx, grn_obj *index,
center_longitude = GRN_GEO_INT2RAD(center->longitude);
center_latitude = GRN_GEO_INT2RAD(center->latitude);
- switch (approximate_type) {
- case GRN_GEO_APPROXIMATE_RECTANGLE :
- distance_raw_func = grn_geo_distance_rectangle_raw;
- break;
- case GRN_GEO_APPROXIMATE_SPHERE :
- distance_raw_func = grn_geo_distance_sphere_raw;
- break;
- case GRN_GEO_APPROXIMATE_ELLIPSOID :
- if (domain == GRN_DB_WGS84_GEO_POINT) {
- distance_raw_func = grn_geo_distance_ellipsoid_raw_wgs84;
- } else {
- distance_raw_func = grn_geo_distance_ellipsoid_raw_tokyo;
- }
- break;
- default :
+ distance_raw_func = grn_geo_resolve_distance_raw_func(ctx,
+ approximate_type,
+ domain);
+ if (!distance_raw_func) {
ERR(GRN_INVALID_ARGUMENT,
"unknown approximate type: <%d>", approximate_type);
goto exit;
- break;
}
switch (distance->header.domain) {
@@ -1700,38 +1716,47 @@ exit :
grn_bool
grn_geo_in_circle(grn_ctx *ctx, grn_obj *point, grn_obj *center,
- grn_obj *radius_or_point)
+ grn_obj *radius_or_point,
+ grn_geo_approximate_type approximate_type)
{
grn_bool r = GRN_FALSE;
grn_obj center_, radius_or_point_;
grn_id domain = point->header.domain;
if (domain == GRN_DB_TOKYO_GEO_POINT || domain == GRN_DB_WGS84_GEO_POINT) {
- double lng0, lat0, lng1, lat1, lng2, lat2, x, y, d;
+ grn_geo_distance_raw_func distance_raw_func;
+ double d;
if (center->header.domain != domain) {
GRN_OBJ_INIT(¢er_, GRN_BULK, 0, domain);
if (grn_obj_cast(ctx, center, ¢er_, 0)) { goto exit; }
center = ¢er_;
}
- GRN_GEO_POINT_VALUE_RADIUS(point, lat0, lng0);
- GRN_GEO_POINT_VALUE_RADIUS(center, lat1, lng1);
- x = (lng1 - lng0) * cos((lat0 + lat1) * 0.5);
- y = (lat1 - lat0);
- d = (x * x) + (y * y);
+
+ distance_raw_func = grn_geo_resolve_distance_raw_func(ctx,
+ approximate_type,
+ domain);
+ if (!distance_raw_func) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "unknown approximate type: <%d>", approximate_type);
+ goto exit;
+ }
+ d = distance_raw_func(ctx,
+ GRN_GEO_POINT_VALUE_RAW(point),
+ GRN_GEO_POINT_VALUE_RAW(center));
switch (radius_or_point->header.domain) {
case GRN_DB_INT32 :
- r = (sqrt(d) * GRN_GEO_RADIUS) <= GRN_INT32_VALUE(radius_or_point);
+ r = d <= GRN_INT32_VALUE(radius_or_point);
break;
case GRN_DB_UINT32 :
- r = (sqrt(d) * GRN_GEO_RADIUS) <= GRN_UINT32_VALUE(radius_or_point);
+ r = d <= GRN_UINT32_VALUE(radius_or_point);
break;
case GRN_DB_INT64 :
- r = (sqrt(d) * GRN_GEO_RADIUS) <= GRN_INT64_VALUE(radius_or_point);
+ r = d <= GRN_INT64_VALUE(radius_or_point);
break;
case GRN_DB_UINT64 :
- r = (sqrt(d) * GRN_GEO_RADIUS) <= GRN_UINT64_VALUE(radius_or_point);
+ r = d <= GRN_UINT64_VALUE(radius_or_point);
break;
case GRN_DB_FLOAT :
- r = (sqrt(d) * GRN_GEO_RADIUS) <= GRN_FLOAT_VALUE(radius_or_point);
+ r = d <= GRN_FLOAT_VALUE(radius_or_point);
break;
case GRN_DB_SHORT_TEXT :
case GRN_DB_TEXT :
@@ -1743,10 +1768,9 @@ grn_geo_in_circle(grn_ctx *ctx, grn_obj *point, grn_obj *center,
case GRN_DB_TOKYO_GEO_POINT :
case GRN_DB_WGS84_GEO_POINT :
if (domain != radius_or_point->header.domain) { /* todo */ goto exit; }
- GRN_GEO_POINT_VALUE_RADIUS(radius_or_point, lat2, lng2);
- x = (lng2 - lng1) * cos((lat1 + lat2) * 0.5);
- y = (lat2 - lat1);
- r = d <= (x * x) + (y * y);
+ r = d <= distance_raw_func(ctx,
+ GRN_GEO_POINT_VALUE_RAW(radius_or_point),
+ GRN_GEO_POINT_VALUE_RAW(center));
break;
default :
goto exit;
Modified: lib/geo.h (+2 -1)
===================================================================
--- lib/geo.h 2011-12-28 15:19:27 +0900 (0a0ee5d)
+++ lib/geo.h 2011-12-28 15:46:47 +0900 (a299771)
@@ -139,7 +139,8 @@ grn_rc grn_selector_geo_in_rectangle(grn_ctx *ctx, grn_obj *obj, grn_obj **args,
int nargs, grn_obj *res, grn_operator op);
grn_bool grn_geo_in_circle(grn_ctx *ctx, grn_obj *point, grn_obj *center,
- grn_obj *radius_or_point);
+ grn_obj *radius_or_point,
+ grn_geo_approximate_type approximate_type);
grn_bool grn_geo_in_rectangle(grn_ctx *ctx, grn_obj *point,
grn_obj *top_left, grn_obj *bottom_right);
grn_bool grn_geo_in_rectangle_raw(grn_ctx *ctx, grn_geo_point *point,
Modified: lib/proc.c (+12 -2)
===================================================================
--- lib/proc.c 2011-12-28 15:19:27 +0900 (3990b36)
+++ lib/proc.c 2011-12-28 15:46:47 +0900 (68e15a9)
@@ -2500,8 +2500,18 @@ func_geo_in_circle(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_
{
grn_obj *obj;
unsigned char r = GRN_FALSE;
- if (nargs == 3) {
- r = grn_geo_in_circle(ctx, args[0], args[1], args[2]);
+ grn_geo_approximate_type type = GRN_GEO_APPROXIMATE_RECTANGLE;
+ switch (nargs) {
+ case 4 :
+ if (grn_geo_resolve_approximate_type(ctx, args[3], &type) != GRN_SUCCESS) {
+ break;
+ }
+ /* fallthru */
+ case 3 :
+ r = grn_geo_in_circle(ctx, args[0], args[1], args[2], type);
+ break;
+ default :
+ break;
}
if ((obj = GRN_PROC_ALLOC(GRN_DB_UINT32, 0))) {
GRN_UINT32_SET(ctx, obj, r);
Modified: test/unit/core/test-command-select-geo.c (+43 -15)
===================================================================
--- test/unit/core/test-command-select-geo.c 2011-12-28 15:19:27 +0900 (c2ed3da)
+++ test/unit/core/test-command-select-geo.c 2011-12-28 15:46:47 +0900 (a3a5ddf)
@@ -21,7 +21,8 @@
#include "../lib/grn-assertions.h"
-void test_default(void);
+void data_default(void);
+void test_default(gconstpointer data);
void data_rectangle(void);
void test_rectangle(gconstpointer data);
void data_sphere(void);
@@ -94,7 +95,21 @@ cut_teardown(void)
}
void
-test_default(void)
+data_default(void)
+{
+#define ADD_DATA(label, use_index) \
+ gcut_add_datum(label, \
+ "use-index", G_TYPE_BOOLEAN, use_index, \
+ NULL)
+
+ ADD_DATA("use index", TRUE);
+ ADD_DATA("no index", FALSE);
+
+#undef ADD_DATA
+}
+
+void
+test_default(gconstpointer data)
{
gdouble yurakucho_latitude = 35.67487;
gdouble yurakucho_longitude = 139.76352;
@@ -117,24 +132,28 @@ test_default(void)
"select Shops "
"--sortby '+_score, +name' "
"--output_columns 'name, _score, location' "
- "--filter 'geo_in_circle(location, \"%s\", %d)' "
+ "--filter 'geo_in_circle(location, \"%s\", %d)%s' "
"--scorer "
"'_score = geo_distance(location, \"%s\") * 1000 * 1000'",
grn_test_location_string(yurakucho_latitude, yurakucho_longitude),
distance,
+ gcut_data_get_boolean(data, "use-index") ? "" : " > 0",
grn_test_location_string(yurakucho_latitude, yurakucho_longitude))));
}
void
data_rectangle(void)
{
-#define ADD_DATA(label, type) \
+#define ADD_DATA(label, type, use_index) \
gcut_add_datum(label, \
"approximate-type", G_TYPE_STRING, type, \
+ "use-index", G_TYPE_BOOLEAN, use_index, \
NULL)
- ADD_DATA("full", "rectangle");
- ADD_DATA("abbreviation", "rect");
+ ADD_DATA("full - use index", "rectangle", TRUE);
+ ADD_DATA("full - no index", "rectangle", FALSE);
+ ADD_DATA("abbreviation - use index", "rect", TRUE);
+ ADD_DATA("abbreviation - no index", "rect", FALSE);
#undef ADD_DATA
}
@@ -165,12 +184,13 @@ test_rectangle(gconstpointer data)
"select Shops "
"--sortby '+_score, +name' "
"--output_columns 'name, _score, location' "
- "--filter 'geo_in_circle(location, \"%s\", %d, \"%s\")' "
+ "--filter 'geo_in_circle(location, \"%s\", %d, \"%s\")%s' "
"--scorer "
"'_score = geo_distance(location, \"%s\", \"%s\") * 1000 * 1000'",
grn_test_location_string(yurakucho_latitude, yurakucho_longitude),
distance,
approximate_type,
+ gcut_data_get_boolean(data, "use-index") ? "" : " > 0",
grn_test_location_string(yurakucho_latitude, yurakucho_longitude),
approximate_type)));
}
@@ -178,13 +198,16 @@ test_rectangle(gconstpointer data)
void
data_sphere(void)
{
-#define ADD_DATA(label, type) \
+#define ADD_DATA(label, type, use_index) \
gcut_add_datum(label, \
"approximate-type", G_TYPE_STRING, type, \
+ "use-index", G_TYPE_BOOLEAN, use_index, \
NULL)
- ADD_DATA("full", "sphere");
- ADD_DATA("abbreviation", "sphr");
+ ADD_DATA("full - use index", "sphere", TRUE);
+ ADD_DATA("full - no index", "sphere", FALSE);
+ ADD_DATA("abbreviation - use index", "sphr", TRUE);
+ ADD_DATA("abbreviation - no index", "sphr", FALSE);
#undef ADD_DATA
}
@@ -215,12 +238,13 @@ test_sphere(gconstpointer data)
"select Shops "
"--sortby '+_score, +name' "
"--output_columns 'name, _score, location' "
- "--filter 'geo_in_circle(location, \"%s\", %d, \"%s\")' "
+ "--filter 'geo_in_circle(location, \"%s\", %d, \"%s\")%s' "
"--scorer "
"'_score = geo_distance(location, \"%s\", \"%s\") * 1000 * 1000'",
grn_test_location_string(yurakucho_latitude, yurakucho_longitude),
distance,
approximate_type,
+ gcut_data_get_boolean(data, "use-index") ? "" : " > 0",
grn_test_location_string(yurakucho_latitude, yurakucho_longitude),
approximate_type)));
}
@@ -228,13 +252,16 @@ test_sphere(gconstpointer data)
void
data_ellipsoid(void)
{
-#define ADD_DATA(label, type) \
+#define ADD_DATA(label, type, use_index) \
gcut_add_datum(label, \
"approximate-type", G_TYPE_STRING, type, \
+ "use-index", G_TYPE_BOOLEAN, use_index, \
NULL)
- ADD_DATA("full", "ellipsoid");
- ADD_DATA("abbreviation", "ellip");
+ ADD_DATA("full - use index", "ellipsoid", TRUE);
+ ADD_DATA("full - no index", "ellipsoid", FALSE);
+ ADD_DATA("abbreviation - use index", "ellip", TRUE);
+ ADD_DATA("abbreviation - no index", "ellip", FALSE);
#undef ADD_DATA
}
@@ -265,12 +292,13 @@ test_ellipsoid(gconstpointer data)
"select Shops "
"--sortby '+_score, +name' "
"--output_columns 'name, _score, location' "
- "--filter 'geo_in_circle(location, \"%s\", %d, \"%s\")' "
+ "--filter 'geo_in_circle(location, \"%s\", %d, \"%s\")%s' "
"--scorer "
"'_score = geo_distance(location, \"%s\", \"%s\") * 1000 * 1000'",
grn_test_location_string(yurakucho_latitude, yurakucho_longitude),
distance,
approximate_type,
+ gcut_data_get_boolean(data, "use-index") ? "" : " > 0",
grn_test_location_string(yurakucho_latitude, yurakucho_longitude),
approximate_type)));
}
Modified: test/unit/core/test-geo.c (+4 -2)
===================================================================
--- test/unit/core/test-geo.c 2011-12-28 15:19:27 +0900 (5065d91)
+++ test/unit/core/test-geo.c 2011-12-28 15:46:47 +0900 (3060ced)
@@ -185,11 +185,13 @@ test_in_circle(void)
cut_assert_true(grn_geo_in_circle(context,
hiiragi_wgs84,
shinjuku_wgs84,
- tokyo_wgs84));
+ tokyo_wgs84,
+ GRN_GEO_APPROXIMATE_RECTANGLE));
cut_assert_false(grn_geo_in_circle(context,
takane_wgs84,
shinjuku_wgs84,
- tokyo_wgs84));
+ tokyo_wgs84,
+ GRN_GEO_APPROXIMATE_RECTANGLE));
}
void