(NULL == CU_add_test(pSuite, "test_lwpoint_interpolate()", test_lwpoint_interpolate)) ||
(NULL == CU_add_test(pSuite, "test_lwline_clip()", test_lwline_clip)) ||
(NULL == CU_add_test(pSuite, "test_lwline_clip_big()", test_lwline_clip_big)) ||
- (NULL == CU_add_test(pSuite, "test_lwmline_clip()", test_lwmline_clip))
+ (NULL == CU_add_test(pSuite, "test_lwmline_clip()", test_lwmline_clip)) ||
+ (NULL == CU_add_test(pSuite, "test_geohash_precision()", test_geohash_precision)) ||
+ (NULL == CU_add_test(pSuite, "test_geohash()", test_geohash))
)
{
CU_cleanup_registry();
lwline_free(line);
}
+void test_geohash_precision(void)
+{
+ BOX3D bbox;
+ int precision = 0;
+
+ bbox.xmin = 23.0;
+ bbox.xmax = 23.0;
+ bbox.ymin = 25.2;
+ bbox.ymax = 25.2;
+ precision = lwgeom_geohash_precision(bbox);
+ //printf("precision %d\n",precision);
+ CU_ASSERT_EQUAL(precision, 20);
+
+ bbox.xmin = 23.0;
+ bbox.ymin = 23.0;
+ bbox.xmax = 23.1;
+ bbox.ymax = 23.1;
+ precision = lwgeom_geohash_precision(bbox);
+ //printf("precision %d\n",precision);
+ CU_ASSERT_EQUAL(precision, 2);
+
+ bbox.xmin = 23.0;
+ bbox.ymin = 23.0;
+ bbox.xmax = 23.0001;
+ bbox.ymax = 23.0001;
+ precision = lwgeom_geohash_precision(bbox);
+ //printf("precision %d\n",precision);
+ CU_ASSERT_EQUAL(precision, 6);
+
+}
+
+void test_geohash(void)
+{
+ LWPOINT *lwpoint = NULL;
+ LWLINE *lwline = NULL;
+ LWMLINE *lwmline = NULL;
+ char *geohash = NULL;
+
+ lwpoint = (LWPOINT*)lwgeom_from_ewkt("POINT(23.0 25.2)", PARSER_CHECK_NONE);
+ geohash = lwgeom_geohash((LWGEOM*)lwpoint);
+ printf("geohash %s\n",geohash);
+ CU_ASSERT_STRING_EQUAL(geohash, "20");
+ lwfree(lwpoint);
+ lwfree(geohash);
+
+ lwline = (LWLINE*)lwgeom_from_ewkt("LINESTRING(23.0 23.0,23.1 23.1)", PARSER_CHECK_NONE);
+ geohash = lwgeom_geohash((LWGEOM*)lwline);
+ printf("geohash %s\n",geohash);
+ CU_ASSERT_STRING_EQUAL(geohash, "20");
+ lwfree(lwline);
+ lwfree(geohash);
+
+ lwline = (LWLINE*)lwgeom_from_ewkt("LINESTRING(23.0 23.0,23.001 23.001)", PARSER_CHECK_NONE);
+ geohash = lwgeom_geohash((LWGEOM*)lwline);
+ printf("geohash %s\n",geohash);
+ CU_ASSERT_STRING_EQUAL(geohash, "20");
+ lwfree(lwline);
+ lwfree(geohash);
+
+ lwmline = (LWMLINE*)lwgeom_from_ewkt("MULTILINESTRING((23.0 23.0,23.1 23.1),(23.0 23.0,23.1 23.1))", PARSER_CHECK_NONE);
+ geohash = lwgeom_geohash((LWGEOM*)lwmline);
+ printf("geohash %s\n",geohash);
+ CU_ASSERT_STRING_EQUAL(geohash, "20");
+ lwfree(lwmline);
+ lwfree(geohash);
+}
+
+
void test_lwline_clip(void);
void test_lwline_clip_big(void);
void test_lwmline_clip(void);
-
+void test_geohash_precision(void);
+void test_geohash(void);
* pointers to the serialized form (POINTARRAYs).
*/
LWGEOM *lwgeom_deserialize(uchar *serializedform);
-
+BOX3D *lwgeom_compute_box3d(const LWGEOM *geom);
/******************************************************************
LWMCURVE *lwmcurve_deserialize(uchar *serialized_form);
LWMSURFACE *lwmsurface_deserialize(uchar *serialized_form);
-LWGEOM *lwcollection_getsubgeom(LWCOLLECTION *, int);
-
+LWGEOM *lwcollection_getsubgeom(LWCOLLECTION *col, int gnum);
+BOX3D *lwcollection_compute_box3d(LWCOLLECTION *col);
/******************************************************************
return NULL;
}
+
+int lwgeom_geohash_precision(BOX3D bbox)
+{
+ double minx, miny, maxx, maxy;
+ double latmax, latmin, lonmax, lonmin;
+ double lonwidth, latwidth;
+ double latmaxadjust, lonmaxadjust, latminadjust, lonminadjust;
+ int precision = 0;
+
+ /* Get the bounding box, return error if things don't work out. */
+ minx = bbox.xmin;
+ miny = bbox.ymin;
+ maxx = bbox.xmax;
+ maxy = bbox.ymax;
+
+ if( minx == maxx && miny == maxy )
+ {
+ /* It's a point. Doubles have 51 bits of precision.
+ ** 2 * 51 / 5 == 20 */
+ return 20;
+ }
+
+ lonmin = -180.0;
+ latmin = -90.0;
+ lonmax = 180.0;
+ latmax = 90.0;
+
+ /* Shrink a world bounding box until one of the edges interferes with the
+ ** bounds of our rectangle. */
+ while( 1 )
+ {
+ lonwidth = lonmax - lonmin;
+ latwidth = latmax - latmin;
+ latmaxadjust = lonmaxadjust = latminadjust = lonminadjust = 0.0;
+
+ if( minx > lonmin + lonwidth / 2.0 )
+ {
+ lonminadjust = lonwidth / 2.0;
+ }
+ else if ( maxx < lonmax - lonwidth / 2.0 )
+ {
+ lonmaxadjust = -1 * lonwidth / 2.0;
+ }
+ if( miny > latmin + latwidth / 2.0 )
+ {
+ latminadjust = latwidth / 2.0;
+ }
+ else if (maxy < latmax - latwidth / 2.0 )
+ {
+ latmaxadjust = -1 * latwidth / 2.0;
+ }
+ if ( (lonminadjust || lonmaxadjust) && (latminadjust || latmaxadjust ) )
+ {
+ latmin += latminadjust;
+ lonmin += lonminadjust;
+ latmax += latmaxadjust;
+ lonmax += lonmaxadjust;
+ precision++;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ /* Each adjustment above corresponds to 2 bits of storage in the
+ ** geohash. Each geohash character can contain 5 bits of information.
+ ** So geohashes have even lengths. 2 characters corresponds to 10 bits
+ ** of storage, which is 5 adjustments. */
+ return 2 * ( precision / 5 );
+}
+
+char *lwgeom_geohash(const LWGEOM *lwgeom)
+{
+ BOX3D *bbox = NULL;
+ int precision = 0;
+ double lat, lon;
+
+ bbox = lwgeom_compute_box3d(lwgeom);
+ if( ! bbox ) return NULL;
+
+ if ( bbox->xmin < -180 || bbox->ymin < -90 || bbox->xmax > 180 || bbox->ymax > 90 )
+ {
+ lwerror("Geohash requires inputs in decimal degrees.");
+ lwfree(bbox);
+ return NULL;
+ }
+
+ /* What is the center of our geometry? */
+ lon = bbox->xmin + (bbox->xmax - bbox->xmin) / 2;
+ lat = bbox->ymin + (bbox->ymax - bbox->ymin) / 2;
+
+ precision = lwgeom_geohash_precision(*bbox);
+
+ lwfree(bbox);
+
+ /* Return the geohash of the center, with a precision determined by the
+ ** extent of the bounds. */
+ return geohash_point(lat, lon, precision);
+}
+
+static char *base32 = "0123456789bcdefghjkmnpqrstuvwxyz";
+
+char *geohash_point(double latitude, double longitude, int precision)
+{
+ int is_even=1, i=0;
+ double lat[2], lon[2], mid;
+ char bits[] = {16,8,4,2,1};
+ int bit=0, ch=0;
+ char *geohash = NULL;
+
+ geohash = lwalloc(precision + 1);
+
+ lat[0] = -90.0; lat[1] = 90.0;
+ lon[0] = -180.0; lon[1] = 180.0;
+
+ while (i < precision)
+ {
+ if (is_even)
+ {
+ mid = (lon[0] + lon[1]) / 2;
+ if (longitude > mid)
+ {
+ ch |= bits[bit];
+ lon[0] = mid;
+ }
+ else
+ {
+ lon[1] = mid;
+ }
+ }
+ else
+ {
+ mid = (lat[0] + lat[1]) / 2;
+ if (latitude > mid)
+ {
+ ch |= bits[bit];
+ lat[0] = mid;
+ }
+ else
+ {
+ lat[1] = mid;
+ }
+ }
+
+ is_even = !is_even;
+ if (bit < 4)
+ {
+ bit++;
+ }
+ else
+ {
+ geohash[i++] = base32[ch];
+ bit = 0;
+ ch = 0;
+ }
+ }
+ geohash[i] = 0;
+ return geohash;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
int lwpoint_interpolate(const POINT4D *p1, const POINT4D *p2, POINT4D *p, int ndims, int ordinate, double interpolation_value);
LWCOLLECTION *lwline_clip_to_ordinate_range(LWLINE *line, int ordinate, double from, double to);
LWCOLLECTION *lwmline_clip_to_ordinate_range(LWMLINE *mline, int ordinate, double from, double to);
+
+int lwgeom_geohash_precision(BOX3D bbox);
+char *lwgeom_geohash(const LWGEOM *lwgeom);
+char *geohash_point(double latitude, double longitude, int precision);
+
};
+BOX3D *lwcollection_compute_box3d(LWCOLLECTION *col)
+{
+ int i;
+ BOX3D *boxfinal = NULL;
+ BOX3D *boxtmp1 = NULL;
+ BOX3D *boxtmp2 = NULL;
+ for ( i = 0; i < col->ngeoms; i++ )
+ {
+ if( col->geoms[i] ) {
+ switch( TYPE_GETTYPE(col->geoms[i]->type) )
+ {
+ case POINTTYPE:
+ boxtmp1 = lwpoint_compute_box3d((LWPOINT*)(col->geoms[i]));
+ break;
+ case LINETYPE:
+ boxtmp1 = lwline_compute_box3d((LWLINE*)(col->geoms[i]));
+ break;
+ case POLYGONTYPE:
+ boxtmp1 = lwpoly_compute_box3d((LWPOLY*)(col->geoms[i]));
+ break;
+ case CIRCSTRINGTYPE:
+ boxtmp1 = lwcircstring_compute_box3d((LWCIRCSTRING *)(col->geoms[i]));
+ break;
+ case COMPOUNDTYPE:
+ case CURVEPOLYTYPE:
+ case MULTIPOINTTYPE:
+ case MULTILINETYPE:
+ case MULTIPOLYGONTYPE:
+ case MULTICURVETYPE:
+ case MULTISURFACETYPE:
+ case COLLECTIONTYPE:
+ boxtmp1 = lwcollection_compute_box3d((LWCOLLECTION*)(col->geoms[i]));
+ boxfinal = box3d_union(boxtmp1, boxtmp2);
+ break;
+ }
+ boxtmp2 = boxfinal;
+ boxfinal = box3d_union(boxtmp1, boxtmp2);
+ if( boxtmp1 && boxtmp1 != boxfinal )
+ {
+ lwfree(boxtmp1);
+ boxtmp1 = NULL;
+ }
+ if( boxtmp2 && boxtmp2 != boxfinal )
+ {
+ lwfree(boxtmp2);
+ boxtmp2 = NULL;
+ }
+ }
+ }
+ return boxfinal;
+}
}
}
+BOX3D *lwgeom_compute_box3d(const LWGEOM *lwgeom)
+{
+ if( ! lwgeom ) return NULL;
+
+ switch(TYPE_GETTYPE(lwgeom->type))
+ {
+ case POINTTYPE:
+ return lwpoint_compute_box3d((LWPOINT *)lwgeom);
+ case LINETYPE:
+ return lwline_compute_box3d((LWLINE *)lwgeom);
+ case CIRCSTRINGTYPE:
+ return lwcircstring_compute_box3d((LWCIRCSTRING *)lwgeom);
+ case POLYGONTYPE:
+ return lwpoly_compute_box3d((LWPOLY *)lwgeom);
+ case COMPOUNDTYPE:
+ case CURVEPOLYTYPE:
+ case MULTIPOINTTYPE:
+ case MULTILINETYPE:
+ case MULTICURVETYPE:
+ case MULTIPOLYGONTYPE:
+ case MULTISURFACETYPE:
+ case COLLECTIONTYPE:
+ return lwcollection_compute_box3d((LWCOLLECTION *)lwgeom);
+ }
+ /* Never get here, please. */
+ return NULL;
+}
+
int
lwgeom_compute_box2d_p(LWGEOM *lwgeom, BOX2DFLOAT4 *buf)
{