From 42ce299b7c0d6dc7c4be41eb8a6747b164a0ebe8 Mon Sep 17 00:00:00 2001 From: Paul Ramsey Date: Tue, 23 Oct 2012 22:17:12 +0000 Subject: [PATCH] (#2026) fix performance regression in geography distance calculation git-svn-id: http://svn.osgeo.org/postgis/trunk@10531 b70326c6-7e19-0410-871a-916f4a2858ee --- NEWS | 1 + liblwgeom/g_box.c | 6 ++++++ liblwgeom/liblwgeom.h.in | 4 ++++ liblwgeom/liblwgeom_internal.h | 1 + liblwgeom/lwgeom.c | 31 ++++++++++++++++++++++++++++++- postgis/geography_measurement.c | 4 ++++ 6 files changed, 46 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 319edbbe6ef..78d34eca986 100644 --- a/NEWS +++ b/NEWS @@ -83,6 +83,7 @@ PostGIS 2.1.0 - #1957, ST_Distance to a one-point LineString returns NULL - #1976, Geography point-in-ring code overhauled for more reliability - #1981, cleanup of unused variables causing warnings with gcc 4.6+ + - #2026, improve performance of distance calculations - #2057, Fixed linking issue for raster2psql to libpq PostGIS 2.0.1 diff --git a/liblwgeom/g_box.c b/liblwgeom/g_box.c index 90763f6469f..5fd08b69454 100644 --- a/liblwgeom/g_box.c +++ b/liblwgeom/g_box.c @@ -26,6 +26,12 @@ void gbox_init(GBOX *gbox) memset(gbox, 0, sizeof(GBOX)); } +GBOX* gbox_clone(const GBOX *gbox) +{ + GBOX *g = lwalloc(sizeof(GBOX)); + memcpy(g, gbox, sizeof(GBOX)); + return g; +} /* TODO to be removed */ BOX3D* box3d_from_gbox(const GBOX *gbox) diff --git a/liblwgeom/liblwgeom.h.in b/liblwgeom/liblwgeom.h.in index 595364bfffe..03b4c1dc5b4 100644 --- a/liblwgeom/liblwgeom.h.in +++ b/liblwgeom/liblwgeom.h.in @@ -681,6 +681,10 @@ extern void lwgeom_drop_srid(LWGEOM *lwgeom); * NULL if the geometry is empty. */ extern void lwgeom_add_bbox(LWGEOM *lwgeom); +/** +* Compute a box for geom and all sub-geometries, if not already computed +*/ +extern void lwgeom_add_bbox_deep(LWGEOM *lwgeom, GBOX *gbox); /** * Get a non-empty geometry bounding box, computing and diff --git a/liblwgeom/liblwgeom_internal.h b/liblwgeom/liblwgeom_internal.h index 89491bf231b..87b38a90c0e 100644 --- a/liblwgeom/liblwgeom_internal.h +++ b/liblwgeom/liblwgeom_internal.h @@ -330,6 +330,7 @@ GBOX *box2d_clone(const GBOX *lwgeom); LWLINE *lwline_clone_deep(const LWLINE *lwgeom); LWPOLY *lwpoly_clone_deep(const LWPOLY *lwgeom); LWCOLLECTION *lwcollection_clone_deep(const LWCOLLECTION *lwgeom); +GBOX *gbox_clone(const GBOX *gbox); /* * Startpoint diff --git a/liblwgeom/lwgeom.c b/liblwgeom/lwgeom.c index e03cb5330a7..54dd155f949 100644 --- a/liblwgeom/lwgeom.c +++ b/liblwgeom/lwgeom.c @@ -565,7 +565,7 @@ void lwgeom_add_bbox(LWGEOM *lwgeom) { /* an empty LWGEOM has no bbox */ - if( lwgeom_is_empty(lwgeom) ) return; + if ( lwgeom_is_empty(lwgeom) ) return; if ( lwgeom->bbox ) return; FLAGS_SET_BBOX(lwgeom->flags, 1); @@ -573,6 +573,35 @@ lwgeom_add_bbox(LWGEOM *lwgeom) lwgeom_calculate_gbox(lwgeom, lwgeom->bbox); } +void +lwgeom_add_bbox_deep(LWGEOM *lwgeom, GBOX *gbox) +{ + if ( lwgeom_is_empty(lwgeom) ) return; + + FLAGS_SET_BBOX(lwgeom->flags, 1); + + if ( ! ( gbox || lwgeom->bbox ) ) + { + lwgeom->bbox = gbox_new(lwgeom->flags); + lwgeom_calculate_gbox(lwgeom, lwgeom->bbox); + } + else if ( gbox && ! lwgeom->bbox ) + { + lwgeom->bbox = gbox_clone(gbox); + } + + if ( lwgeom_is_collection(lwgeom) ) + { + int i; + LWCOLLECTION *lwcol = (LWCOLLECTION*)lwgeom; + + for ( i = 0; i < lwcol->ngeoms; i++ ) + { + lwgeom_add_bbox_deep(lwcol->geoms[i], lwgeom->bbox); + } + } +} + const GBOX * lwgeom_get_bbox(const LWGEOM *lwg) { diff --git a/postgis/geography_measurement.c b/postgis/geography_measurement.c index f3ec0c106ae..c4ee647e80c 100644 --- a/postgis/geography_measurement.c +++ b/postgis/geography_measurement.c @@ -87,6 +87,10 @@ Datum geography_distance_uncached(PG_FUNCTION_ARGS) PG_RETURN_NULL(); } + /* Make sure we have boxes attached */ + lwgeom_add_bbox_deep(lwgeom1, NULL); + lwgeom_add_bbox_deep(lwgeom2, NULL); + distance = lwgeom_distance_spheroid(lwgeom1, lwgeom2, &s, FP_TOLERANCE); /* Clean up */