null+****@clear*****
null+****@clear*****
2010年 8月 4日 (水) 18:05:21 JST
Kouhei Sutou 2010-08-04 09:05:21 +0000 (Wed, 04 Aug 2010) New Revision: 0e36d5b8a1fe71bb318be035c6e5275ad3026660 Log: split geo related functions to geo.[ch]. Added files: lib/geo.c lib/geo.h Modified files: lib/Makefile.am test/unit/core/Makefile.am test/unit/core/test-table-patricia-trie-cursor.c test/unit/lib/grn-test-utils.h Modified: lib/Makefile.am (+2 -2) =================================================================== --- lib/Makefile.am 2010-08-04 01:33:59 +0000 (b7e1fb9) +++ lib/Makefile.am 2010-08-04 09:05:21 +0000 (4cfd42f) @@ -5,14 +5,14 @@ AM_CFLAGS = -fno-strict-aliasing $(COVERAGE_CFLAGS) DEFAULT_INCLUDES = -I$(top_builddir) -I$(top_srcdir) DEFS += -D_REENTRANT -DGROONGA_VERSION=\"$(GROONGA_VERSION)\" -libgroonga_la_SOURCES = io.c str.c nfkc.c snip.c query.c store.c com.c ql.c scm.c ctx.c hash.c db.c pat.c ii.c token.c proc.c expr.c util.c module.c output.c +libgroonga_la_SOURCES = io.c str.c nfkc.c snip.c query.c store.c com.c ql.c scm.c ctx.c hash.c db.c pat.c ii.c token.c proc.c expr.c util.c module.c output.c geo.c libgroonga_la_LDFLAGS = \ -version-info 0:0:0 \ -no-undefined \ $(WINDOWS_LDFLAGS) -noinst_HEADERS = com.h io.h ql.h nfkc.h groonga_in.h snip.h store.h str.h ctx.h hash.h db.h pat.h ii.h token.h proc.h util.h module.h output.h +noinst_HEADERS = com.h io.h ql.h nfkc.h groonga_in.h snip.h store.h str.h ctx.h hash.h db.h pat.h ii.h token.h proc.h util.h module.h output.h geo.h EXTRA_DIST = ecmascript.c ecmascript.h ecmascript.y Added: lib/geo.c (+240 -0) 100644 =================================================================== --- /dev/null +++ lib/geo.c 2010-08-04 09:05:21 +0000 (7c56c10) @@ -0,0 +1,240 @@ +/* -*- c-basic-offset: 2 -*- */ +/* Copyright(C) 2009-2010 Brazil + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <math.h> +#include <string.h> +#include <stdlib.h> +#include "geo.h" +#include "ii.h" +#include "db.h" + +#define GEO_RESOLUTION 3600000 +#define GEO_RADIOUS 6357303 +#define GEO_BES_C1 6334834 +#define GEO_BES_C2 6377397 +#define GEO_BES_C3 0.006674 +#define GEO_GRS_C1 6335439 +#define GEO_GRS_C2 6378137 +#define GEO_GRS_C3 0.006694 +#define GEO_INT2RAD(x) ((M_PI / (GEO_RESOLUTION * 180)) * x) + +unsigned +grn_geo_in_circle(grn_ctx *ctx, grn_obj *point, grn_obj *center, + grn_obj *radius_or_point) +{ + unsigned 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; + 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_; + } + lng0 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(point))->longitude); + lat0 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(point))->latitude); + lng1 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(center))->longitude); + lat1 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(center))->latitude); + x = (lng1 - lng0) * cos((lat0 + lat1) * 0.5); + y = (lat1 - lat0); + d = (x * x) + (y * y); + switch (radius_or_point->header.domain) { + case GRN_DB_INT32 : + r = (sqrt(d) * GEO_RADIOUS) <= GRN_INT32_VALUE(radius_or_point); + break; + case GRN_DB_UINT32 : + r = (sqrt(d) * GEO_RADIOUS) <= GRN_UINT32_VALUE(radius_or_point); + break; + case GRN_DB_INT64 : + r = (sqrt(d) * GEO_RADIOUS) <= GRN_INT64_VALUE(radius_or_point); + break; + case GRN_DB_UINT64 : + r = (sqrt(d) * GEO_RADIOUS) <= GRN_UINT64_VALUE(radius_or_point); + break; + case GRN_DB_FLOAT : + r = (sqrt(d) * GEO_RADIOUS) <= GRN_FLOAT_VALUE(radius_or_point); + break; + case GRN_DB_SHORT_TEXT : + case GRN_DB_TEXT : + case GRN_DB_LONG_TEXT : + GRN_OBJ_INIT(&radius_or_point_, GRN_BULK, 0, domain); + if (grn_obj_cast(ctx, radius_or_point, &radius_or_point_, 0)) { goto exit; } + radius_or_point = &radius_or_point_; + /* fallthru */ + case GRN_DB_TOKYO_GEO_POINT : + case GRN_DB_WGS84_GEO_POINT : + if (domain != radius_or_point->header.domain) { /* todo */ goto exit; } + lng2 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(radius_or_point))->longitude); + lat2 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(radius_or_point))->latitude); + x = (lng2 - lng1) * cos((lat1 + lat2) * 0.5); + y = (lat2 - lat1); + r = d <= (x * x) + (y * y); + break; + default : + goto exit; + } + } else { + /* todo */ + } +exit : + return r; +} + +unsigned +grn_geo_in_rectangle(grn_ctx *ctx, grn_obj *point, + grn_obj *top_left, grn_obj *bottom_right) +{ + unsigned r = GRN_FALSE; + grn_obj top_left_, bottom_right_; + grn_geo_point *p, *p1, *p2; + grn_id domain = point->header.domain; + if (domain == GRN_DB_TOKYO_GEO_POINT || domain == GRN_DB_WGS84_GEO_POINT) { + if (top_left->header.domain != domain) { + GRN_OBJ_INIT(&top_left_, GRN_BULK, 0, domain); + if (grn_obj_cast(ctx, top_left, &top_left_, 0)) { goto exit; } + top_left = &top_left_; + } + if (bottom_right->header.domain != domain) { + GRN_OBJ_INIT(&bottom_right_, GRN_BULK, 0, domain); + if (grn_obj_cast(ctx, bottom_right, &bottom_right_, 0)) { goto exit; } + bottom_right = &bottom_right_; + } + p = ((grn_geo_point *)GRN_BULK_HEAD(point)); + p1 = ((grn_geo_point *)GRN_BULK_HEAD(top_left)); + p2 = ((grn_geo_point *)GRN_BULK_HEAD(bottom_right)); + r = ((p1->longitude <= p->longitude) && (p->longitude <= p2->longitude) && + (p2->latitude <= p->latitude) && (p->latitude <= p1->latitude)); + } else { + /* todo */ + } +exit : + return r; +} + +double +grn_geo_distance(grn_ctx *ctx, grn_obj *point1, grn_obj *point2) +{ + double d = 0; + grn_obj point2_; + grn_id domain = point1->header.domain; + if (domain == GRN_DB_TOKYO_GEO_POINT || domain == GRN_DB_WGS84_GEO_POINT) { + double lng1, lat1, lng2, lat2, x, y; + if (point2->header.domain != domain) { + GRN_OBJ_INIT(&point2_, GRN_BULK, 0, domain); + if (grn_obj_cast(ctx, point2, &point2_, 0)) { goto exit; } + point2 = &point2_; + } + lng1 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(point1))->longitude); + lat1 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(point1))->latitude); + lng2 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(point2))->longitude); + lat2 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(point2))->latitude); + x = (lng2 - lng1) * cos((lat1 + lat2) * 0.5); + y = (lat2 - lat1); + d = sqrt((x * x) + (y * y)) * GEO_RADIOUS; + } else { + /* todo */ + } +exit : + return d; +} + +double +grn_geo_distance2(grn_ctx *ctx, grn_obj *point1, grn_obj *point2) +{ + double d = 0; + grn_obj point2_; + grn_id domain = point1->header.domain; + if (domain == GRN_DB_TOKYO_GEO_POINT || domain == GRN_DB_WGS84_GEO_POINT) { + double lng1, lat1, lng2, lat2, x, y; + if (point2->header.domain != domain) { + GRN_OBJ_INIT(&point2_, GRN_BULK, 0, domain); + if (grn_obj_cast(ctx, point2, &point2_, 0)) { goto exit; } + point2 = &point2_; + } + lng1 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(point1))->longitude); + lat1 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(point1))->latitude); + lng2 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(point2))->longitude); + lat2 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(point2))->latitude); + x = sin(fabs(lng2 - lng1) * 0.5); + y = sin(fabs(lat2 - lat1) * 0.5); + d = asin(sqrt((y * y) + cos(lat1) * cos(lat2) * x * x)) * 2 * GEO_RADIOUS; + } else { + /* todo */ + } +exit : + return d; +} + +double +grn_geo_distance3(grn_ctx *ctx, grn_obj *point1, grn_obj *point2) +{ + double d = 0; + grn_obj point2_; + grn_id domain = point1->header.domain; + switch (domain) { + case GRN_DB_TOKYO_GEO_POINT : + { + double lng1, lat1, lng2, lat2, p, q, r, m, n, x, y; + if (point2->header.domain != domain) { + GRN_OBJ_INIT(&point2_, GRN_BULK, 0, domain); + if (grn_obj_cast(ctx, point2, &point2_, 0)) { goto exit; } + point2 = &point2_; + } + lng1 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(point1))->longitude); + lat1 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(point1))->latitude); + lng2 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(point2))->longitude); + lat2 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(point2))->latitude); + p = (lat1 + lat2) * 0.5; + q = (1 - GEO_BES_C3 * sin(p) * sin(p)); + r = sqrt(q); + m = GEO_BES_C1 / (q * r); + n = GEO_BES_C2 / r; + x = n * cos(p) * fabs(lng1 - lng2); + y = m * fabs(lat1 - lat2); + d = sqrt((x * x) + (y * y)); + } + break; + case GRN_DB_WGS84_GEO_POINT : + { + double lng1, lat1, lng2, lat2, p, q, r, m, n, x, y; + if (point2->header.domain != domain) { + GRN_OBJ_INIT(&point2_, GRN_BULK, 0, domain); + if (grn_obj_cast(ctx, point2, &point2_, 0)) { goto exit; } + point2 = &point2_; + } + lng1 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(point1))->longitude); + lat1 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(point1))->latitude); + lng2 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(point2))->longitude); + lat2 = GEO_INT2RAD(((grn_geo_point *)GRN_BULK_HEAD(point2))->latitude); + p = (lat1 + lat2) * 0.5; + q = (1 - GEO_GRS_C3 * sin(p) * sin(p)); + r = sqrt(q); + m = GEO_GRS_C1 / (q * r); + n = GEO_GRS_C2 / r; + x = n * cos(p) * fabs(lng1 - lng2); + y = m * fabs(lat1 - lat2); + d = sqrt((x * x) + (y * y)); + } + break; + default : + /* todo */ + break; + } +exit : + return d; +} Added: lib/geo.h (+40 -0) 100644 =================================================================== --- /dev/null +++ lib/geo.h 2010-08-04 09:05:21 +0000 (e930791) @@ -0,0 +1,40 @@ +/* -*- c-basic-offset: 2 -*- */ +/* Copyright(C) 2009-2010 Brazil + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#ifndef GRN_GEO_H +#define GRN_GEO_H + +#ifndef GROONGA_IN_H +#include "groonga_in.h" +#endif /* GROONGA_IN_H */ + +#ifdef __cplusplus +extern "C" { +#endif + +unsigned grn_geo_in_circle(grn_ctx *ctx, grn_obj *point, grn_obj *center, + grn_obj *radius_or_point); +unsigned grn_geo_in_rectangle(grn_ctx *ctx, grn_obj *point, + grn_obj *top_left, grn_obj *bottom_right); +double grn_geo_distance(grn_ctx *ctx, grn_obj *point1, grn_obj *point2); +double grn_geo_distance2(grn_ctx *ctx, grn_obj *point1, grn_obj *point2); +double grn_geo_distance3(grn_ctx *ctx, grn_obj *point1, grn_obj *point2); + +#ifdef __cplusplus +} +#endif + +#endif /* GRN_GEO_H */ Modified: test/unit/core/Makefile.am (+3 -1) =================================================================== --- test/unit/core/Makefile.am 2010-08-04 01:33:59 +0000 (b61e469) +++ test/unit/core/Makefile.am 2010-08-04 09:05:21 +0000 (f526093) @@ -45,7 +45,8 @@ noinst_LTLIBRARIES = \ test-command-select-sort.la \ test-command-select-prefix-search.la \ test-command-cache-limit.la \ - test-command-delete.la + test-command-delete.la \ + test-geo.la endif INCLUDES = \ @@ -115,3 +116,4 @@ test_command_select_sort_la_SOURCES = test-command-select-sort.c test_command_select_prefix_search_la_SOURCES = test-command-select-prefix-search.c test_command_cache_limit_la_SOURCES = test-command-cache-limit.c test_command_delete_la_SOURCES = test-command-delete.c +test_geo_la_SOURCES = test-geo.c Modified: test/unit/core/test-table-patricia-trie-cursor.c (+2 -3) =================================================================== --- test/unit/core/test-table-patricia-trie-cursor.c 2010-08-04 01:33:59 +0000 (5f4185d) +++ test/unit/core/test-table-patricia-trie-cursor.c 2010-08-04 09:05:21 +0000 (6bc3827) @@ -25,12 +25,11 @@ #include "../lib/grn-assertions.h" #define COORDINATE(hours, minutes, seconds) \ - ((hours) * 3600 + (minutes) * 60 + (seconds)) * 1000 + GRN_TEST_GEO_COORDINATE(hours, minutes, seconds) #define POINT(latitude_hours, latitude_minutes, latitude_seconds, \ longitude_hours, longitude_minutes, longitude_seconds) \ - g_strdup_printf( \ - "%dx%d", \ + GRN_TEST_GEO_POINT_STRING( \ COORDINATE(latitude_hours, latitude_minutes, latitude_seconds), \ COORDINATE(longitude_hours, longitude_minutes, longitude_seconds)) Modified: test/unit/lib/grn-test-utils.h (+6 -0) =================================================================== --- test/unit/lib/grn-test-utils.h 2010-08-04 01:33:59 +0000 (7fd609a) +++ test/unit/lib/grn-test-utils.h 2010-08-04 09:05:21 +0000 (25e6ddb) @@ -33,6 +33,12 @@ #define GRN_TEST_ENV_N_PROCESSES "GRN_TEST_N_PROCESSES" #define GRN_TEST_ENV_PROCESS_NUMBER "GRN_TEST_PROCESS_NUMBER" +#define GRN_TEST_GEO_COORDINATE(hours, minutes, seconds) \ + ((hours) * 3600 + (minutes) * 60 + (seconds)) * 1000 + +#define GRN_TEST_GEO_POINT_STRING(latitude, longitude) \ + g_strdup_printf("%dx%d", latitude, longitude) + typedef void (*grn_test_set_parameters_func) (void); const gchar *grn_rc_to_string (grn_rc rc);