null+****@clear*****
null+****@clear*****
2010年 7月 6日 (火) 17:03:17 JST
Kouhei Sutou 2010-07-06 08:03:17 +0000 (Tue, 06 Jul 2010) New Revision: cb9d35b82c190a607e9c74189f7aa366cfd8daab Log: support geo point in degree. Modified files: lib/db.c test/unit/core/test-cast-basic.c Modified: lib/db.c (+43 -3) =================================================================== --- lib/db.c 2010-07-06 07:53:39 +0000 (52985cb) +++ lib/db.c 2010-07-06 08:03:17 +0000 (8030a77) @@ -3651,6 +3651,11 @@ grn_obj_is_persistent(grn_ctx *ctx, grn_obj *obj) GRN_BOOL_SET(ctx, dest, value_ < -DBL_EPSILON || DBL_EPSILON < value_);\ } +#define DEGREE2MSEC(degree)\ + (((int)degree * 60 * 60 * 1000) +\ + (((int)(degree * 100) % 100) * 60 * 1000) +\ + (((int)(degree * 10000) % 100) * 1000) +\ + ((int)(degree * 10000000) % 1000)) grn_rc grn_obj_cast(grn_ctx *ctx, grn_obj *src, grn_obj *dest, int addp) @@ -3770,12 +3775,46 @@ grn_obj_cast(grn_ctx *ctx, grn_obj *src, grn_obj *dest, int addp) case GRN_DB_WGS84_GEO_POINT : { int latitude, longitude; + double degree; const char *cur, *str = GRN_TEXT_VALUE(src); const char *str_end = GRN_BULK_CURR(src); + char *end; + grn_obj buf, *buf_p = NULL; latitude = grn_atoi(str, str_end, &cur); - if (cur + 1 < str_end) { - longitude = grn_atoi(cur + 1, str_end, &cur); - if (cur == str_end) { + if (cur[0] == '.') { + GRN_TEXT_INIT(&buf, 0); + GRN_TEXT_PUT(ctx, &buf, str, GRN_TEXT_LEN(src)); + GRN_TEXT_PUTC(ctx, &buf, '\0'); + buf_p = &buf; + errno = 0; + degree = strtod(GRN_TEXT_VALUE(buf_p), &end); + if (errno) { + rc = GRN_INVALID_ARGUMENT; + } else { + latitude = DEGREE2MSEC(degree); + cur = str + (end - GRN_TEXT_VALUE(buf_p)); + } + } + if (!rc && (cur[0] == 'x' || cur[0] == ',') && cur + 1 < str_end) { + const char *c = cur + 1; + longitude = grn_atoi(c, str_end, &cur); + if (cur[0] == '.') { + if (!buf_p) { + GRN_TEXT_INIT(&buf, 0); + GRN_TEXT_PUT(ctx, &buf, str, GRN_TEXT_LEN(src)); + GRN_TEXT_PUTC(ctx, &buf, '\0'); + buf_p = &buf; + } + errno = 0; + degree = strtod(GRN_TEXT_VALUE(buf_p) + (c - str), &end); + if (errno) { + rc = GRN_INVALID_ARGUMENT; + } else { + longitude = DEGREE2MSEC(degree); + cur = str + (end - GRN_TEXT_VALUE(buf_p)); + } + } + if (!rc && cur == str_end) { GRN_GEO_POINT_SET(ctx, dest, latitude, longitude); } else { rc = GRN_INVALID_ARGUMENT; @@ -3783,6 +3822,7 @@ grn_obj_cast(grn_ctx *ctx, grn_obj *src, grn_obj *dest, int addp) } else { rc = GRN_INVALID_ARGUMENT; } + if (buf_p) { GRN_OBJ_FIN(ctx, buf_p); } } break; default : Modified: test/unit/core/test-cast-basic.c (+59 -1) =================================================================== --- test/unit/core/test-cast-basic.c 2010-07-06 07:53:39 +0000 (4cffaa6) +++ test/unit/core/test-cast-basic.c 2010-07-06 08:03:17 +0000 (294184b) @@ -36,7 +36,12 @@ void test_text_to_uint64(void); void test_text_to_float(void); void test_text_to_time(void); void test_text_to_geo_point(void); +void test_text_to_geo_point_comma(void); void test_text_to_geo_point_invalid(void); +void test_text_to_geo_point_in_degree(void); +void test_text_to_geo_point_in_degree_invalid(void); +void test_text_to_geo_point_mixed(void); +void test_text_to_geo_point_mixed_invalid(void); void data_text_error(void); void test_text_error(gconstpointer data); @@ -256,9 +261,20 @@ test_text_to_geo_point(void) } void +test_text_to_geo_point_comma(void) +{ + gint takane_latitude, takane_longitude; + + grn_obj_reinit(&context, &dest, GRN_DB_WGS84_GEO_POINT, 0); + cast_text("130194581,503802073"); + GRN_GEO_POINT_VALUE(&dest, takane_latitude, takane_longitude); + cut_assert_equal_int(130194581, takane_latitude); + cut_assert_equal_int(503802073, takane_longitude); +} + +void test_text_to_geo_point_invalid(void) { - cut_omit("any character is accepted as separator."); grn_obj_reinit(&context, &dest, GRN_DB_WGS84_GEO_POINT, 0); set_text("130194581?503802073"); grn_test_assert_equal_rc(GRN_INVALID_ARGUMENT, @@ -266,6 +282,48 @@ test_text_to_geo_point_invalid(void) } void +test_text_to_geo_point_in_degree(void) +{ + gint takane_latitude, takane_longitude; + + grn_obj_reinit(&context, &dest, GRN_DB_WGS84_GEO_POINT, 0); + cast_text("35.6954581363924x139.564207350021"); + GRN_GEO_POINT_VALUE(&dest, takane_latitude, takane_longitude); + cut_assert_equal_int(130194581, takane_latitude); + cut_assert_equal_int(503802073, takane_longitude); +} + +void +test_text_to_geo_point_in_degree_invalid(void) +{ + grn_obj_reinit(&context, &dest, GRN_DB_WGS84_GEO_POINT, 0); + set_text("35.6954581363924?139.564207350021"); + grn_test_assert_equal_rc(GRN_INVALID_ARGUMENT, + grn_obj_cast(&context, &src, &dest, FALSE)); +} + +void +test_text_to_geo_point_mixed(void) +{ + gint takane_latitude, takane_longitude; + + grn_obj_reinit(&context, &dest, GRN_DB_WGS84_GEO_POINT, 0); + cast_text("35.6954581363924x503802073"); + GRN_GEO_POINT_VALUE(&dest, takane_latitude, takane_longitude); + cut_assert_equal_int(130194581, takane_latitude); + cut_assert_equal_int(503802073, takane_longitude); +} + +void +test_text_to_geo_point_mixed_invalid(void) +{ + grn_obj_reinit(&context, &dest, GRN_DB_WGS84_GEO_POINT, 0); + set_text("35.6954581363924x503802073garbage"); + grn_test_assert_equal_rc(GRN_INVALID_ARGUMENT, + grn_obj_cast(&context, &src, &dest, FALSE)); +} + +void data_text_error(void) { #define ADD_DATA(label, expected, type, text) \