[Groonga-commit] groonga/groonga [master] add low level API for geo.

Back to archive index

null+****@clear***** null+****@clear*****
2010年 8月 5日 (木) 11:54:02 JST


Kouhei Sutou	2010-08-05 02:54:02 +0000 (Thu, 05 Aug 2010)

  New Revision: 48cbe1cb4783945452d41a4cacf059f6b5dc5c24

  Log:
    add low level API for geo.

  Modified files:
    lib/geo.c
    lib/geo.h

  Modified: lib/geo.c (+70 -46)
===================================================================
--- lib/geo.c    2010-08-05 02:30:28 +0000 (c9991cc)
+++ lib/geo.c    2010-08-05 02:54:02 +0000 (8465000)
@@ -113,23 +113,68 @@ exit :
 }
 
 double
+grn_geo_distance_raw(grn_ctx *ctx, grn_geo_point *point1, grn_geo_point *point2)
+{
+  double lng1, lat1, lng2, lat2, x, y;
+
+  lat1 = GRN_GEO_INT2RAD(point1->latitude);
+  lng1 = GRN_GEO_INT2RAD(point1->longitude);
+  lat2 = GRN_GEO_INT2RAD(point2->latitude);
+  lng2 = GRN_GEO_INT2RAD(point2->longitude);
+  x = (lng2 - lng1) * cos((lat1 + lat2) * 0.5);
+  y = (lat2 - lat1);
+  return sqrt((x * x) + (y * y)) * GRN_GEO_RADIOUS;
+}
+
+double
+grn_geo_distance2_raw(grn_ctx *ctx, grn_geo_point *point1, grn_geo_point *point2)
+{
+  double lng1, lat1, lng2, lat2, x, y;
+
+  lat1 = GRN_GEO_INT2RAD(point1->latitude);
+  lng1 = GRN_GEO_INT2RAD(point1->longitude);
+  lat2 = GRN_GEO_INT2RAD(point2->latitude);
+  lng2 = GRN_GEO_INT2RAD(point2->longitude);
+  x = sin(fabs(lng2 - lng1) * 0.5);
+  y = sin(fabs(lat2 - lat1) * 0.5);
+  return asin(sqrt((y * y) + cos(lat1) * cos(lat2) * x * x)) * 2 * GRN_GEO_RADIOUS;
+}
+
+double
+grn_geo_distance3_raw(grn_ctx *ctx, grn_geo_point *point1, grn_geo_point *point2,
+                      int c1, int c2, double c3)
+{
+  double lng1, lat1, lng2, lat2, p, q, r, m, n, x, y;
+
+  lat1 = GRN_GEO_INT2RAD(point1->latitude);
+  lng1 = GRN_GEO_INT2RAD(point1->longitude);
+  lat2 = GRN_GEO_INT2RAD(point2->latitude);
+  lng2 = GRN_GEO_INT2RAD(point2->longitude);
+  p = (lat1 + lat2) * 0.5;
+  q = (1 - c3 * sin(p) * sin(p));
+  r = sqrt(q);
+  m = c1 / (q * r);
+  n = c2 / r;
+  x = n * cos(p) * fabs(lng1 - lng2);
+  y = m * fabs(lat1 - lat2);
+  return sqrt((x * x) + (y * y));
+}
+
+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_;
     }
-    GRN_GEO_POINT_VALUE_RADIUS(point1, lat1, lng1);
-    GRN_GEO_POINT_VALUE_RADIUS(point2, lat2, lng2);
-    x = (lng2 - lng1) * cos((lat1 + lat2) * 0.5);
-    y = (lat2 - lat1);
-    d = sqrt((x * x) + (y * y)) * GRN_GEO_RADIOUS;
+    d = grn_geo_distance_raw(ctx,
+                             GRN_GEO_POINT_VALUE_RAW(point1),
+                             GRN_GEO_POINT_VALUE_RAW(point2));
   } else {
     /* todo */
   }
@@ -144,17 +189,14 @@ grn_geo_distance2(grn_ctx *ctx, grn_obj *point1, grn_obj *point2)
   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_;
     }
-    GRN_GEO_POINT_VALUE_RADIUS(point1, lat1, lng1);
-    GRN_GEO_POINT_VALUE_RADIUS(point2, lat2, lng2);
-    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 * GRN_GEO_RADIOUS;
+    d = grn_geo_distance2_raw(ctx,
+                              GRN_GEO_POINT_VALUE_RAW(point1),
+                              GRN_GEO_POINT_VALUE_RAW(point2));
   } else {
     /* todo */
   }
@@ -170,44 +212,26 @@ grn_geo_distance3(grn_ctx *ctx, grn_obj *point1, 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_;
-      }
-      GRN_GEO_POINT_VALUE_RADIUS(point1, lat1, lng1);
-      GRN_GEO_POINT_VALUE_RADIUS(point2, lat2, lng2);
-      p = (lat1 + lat2) * 0.5;
-      q = (1 - GRN_GEO_BES_C3 * sin(p) * sin(p));
-      r = sqrt(q);
-      m = GRN_GEO_BES_C1 / (q * r);
-      n = GRN_GEO_BES_C2 / r;
-      x = n * cos(p) * fabs(lng1 - lng2);
-      y = m * fabs(lat1 - lat2);
-      d = sqrt((x * x) + (y * 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_;
     }
+    d = grn_geo_distance3_raw(ctx,
+                              GRN_GEO_POINT_VALUE_RAW(point1),
+                              GRN_GEO_POINT_VALUE_RAW(point2),
+                              GRN_GEO_BES_C1, GRN_GEO_BES_C2, GRN_GEO_BES_C3);
     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_;
-      }
-      GRN_GEO_POINT_VALUE_RADIUS(point1, lat1, lng1);
-      GRN_GEO_POINT_VALUE_RADIUS(point2, lat2, lng2);
-      p = (lat1 + lat2) * 0.5;
-      q = (1 - GRN_GEO_GRS_C3 * sin(p) * sin(p));
-      r = sqrt(q);
-      m = GRN_GEO_GRS_C1 / (q * r);
-      n = GRN_GEO_GRS_C2 / r;
-      x = n * cos(p) * fabs(lng1 - lng2);
-      y = m * fabs(lat1 - lat2);
-      d = sqrt((x * x) + (y * 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_;
     }
+    d = grn_geo_distance3_raw(ctx,
+                              GRN_GEO_POINT_VALUE_RAW(point1),
+                              GRN_GEO_POINT_VALUE_RAW(point2),
+                              GRN_GEO_GRS_C1, GRN_GEO_GRS_C2, GRN_GEO_GRS_C3);
     break;
   default :
     /* todo */

  Modified: lib/geo.h (+5 -0)
===================================================================
--- lib/geo.h    2010-08-05 02:30:28 +0000 (f976147)
+++ lib/geo.h    2010-08-05 02:54:02 +0000 (bf03b0e)
@@ -37,6 +37,7 @@ extern "C" {
 #define GRN_GEO_GRS_C3       0.006694
 #define GRN_GEO_INT2RAD(x)   ((M_PI / (GRN_GEO_RESOLUTION * 180)) * (x))
 
+#define GRN_GEO_POINT_VALUE_RAW(obj) (grn_geo_point *)GRN_BULK_HEAD(obj)
 #define GRN_GEO_POINT_VALUE_RADIUS(obj,_latitude,_longitude) do {\
   grn_geo_point *_val = (grn_geo_point *)GRN_BULK_HEAD(obj);\
   _latitude = GRN_GEO_INT2RAD(_val->latitude);\
@@ -50,6 +51,10 @@ unsigned grn_geo_in_rectangle(grn_ctx *ctx, grn_obj *point,
 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);
+double grn_geo_distance_raw(grn_ctx *ctx, grn_geo_point *point1, grn_geo_point *point2);
+double grn_geo_distance2_raw(grn_ctx *ctx, grn_geo_point *point1, grn_geo_point *point2);
+double grn_geo_distance3_raw(grn_ctx *ctx, grn_geo_point *point1, grn_geo_point *point2,
+                             int c1, int c2, double c3);
 
 #ifdef __cplusplus
 }




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