[Groonga-commit] groonga/groonga [master] split geo related functions to geo.[ch].

Back to archive index

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(&center_, GRN_BULK, 0, domain);
+      if (grn_obj_cast(ctx, center, &center_, 0)) { goto exit; }
+      center = &center_;
+    }
+    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);




Groonga-commit メーリングリストの案内
Back to archive index