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