#include "../postgis_config.h"
+/*#define POSTGIS_DEBUG_LEVEL 4*/
+
#include "liblwgeom.h" /* For standard geometry types. */
#include "lwgeom_pg.h" /* For debugging macros. */
#include "gserialized_gist.h"
+#define FLAGS_NDIMS_GIDX(f) ( FLAGS_GET_GEODETIC(f) ? 3 : \
+ FLAGS_GET_M(f) ? 4 : \
+ FLAGS_GET_Z(f) ? 3 : 2 )
+
/* Generate human readable form for GIDX. */
#if POSTGIS_DEBUG_LEVEL > 0
return gpart->flags;
}
+/* Convert a double-based GBOX into a float-based GIDX,
+ ensuring the float box is larger than the double box */
+static int gidx_from_gbox_p(GBOX box, GIDX *a)
+{
+ int ndims;
+
+ ndims = FLAGS_NDIMS_GIDX(box.flags);
+ SET_VARSIZE(a, VARHDRSZ + ndims * 2 * sizeof(float));
+
+ GIDX_SET_MIN(a,0,next_float_down(box.xmin));
+ GIDX_SET_MAX(a,0,next_float_up(box.xmax));
+ GIDX_SET_MIN(a,1,next_float_down(box.ymin));
+ GIDX_SET_MAX(a,1,next_float_up(box.ymax));
+
+ /* Geodetic indexes are always 3d, geocentric x/y/z */
+ if ( FLAGS_GET_GEODETIC(box.flags) )
+ {
+ GIDX_SET_MIN(a,2,next_float_down(box.zmin));
+ GIDX_SET_MAX(a,2,next_float_up(box.zmax));
+ }
+ else
+ {
+ /* Cartesian with Z implies Z is third dimension */
+ if ( FLAGS_GET_Z(box.flags) )
+ {
+ GIDX_SET_MIN(a,2,next_float_down(box.zmin));
+ GIDX_SET_MAX(a,2,next_float_up(box.zmax));
+ }
+ /* M is always fourth dimension, we pad if needed */
+ if ( FLAGS_GET_M(box.flags) )
+ {
+ if ( ! FLAGS_GET_Z(box.flags) )
+ {
+ GIDX_SET_MIN(a,2,-1*FLT_MAX);
+ GIDX_SET_MAX(a,2,FLT_MAX);
+ }
+ GIDX_SET_MIN(a,3,next_float_down(box.mmin));
+ GIDX_SET_MAX(a,3,next_float_up(box.mmax));
+ }
+ }
+
+ POSTGIS_DEBUGF(5, "converted %s to %s", gbox_to_string(&box), gidx_to_string(a));
+
+ return LW_SUCCESS;
+}
+
+/* Convert a gidx to a gbox */
+static void gbox_from_gidx(GIDX *a, GBOX *gbox, int flags)
+{
+ gbox->xmin = (double)GIDX_GET_MIN(a,0);
+ gbox->xmax = (double)GIDX_GET_MAX(a,0);
+
+ gbox->ymin = (double)GIDX_GET_MIN(a,1);
+ gbox->ymax = (double)GIDX_GET_MAX(a,1);
+
+ if ( FLAGS_GET_Z(flags) ) {
+ gbox->zmin = (double)GIDX_GET_MIN(a,2);
+ gbox->zmax = (double)GIDX_GET_MAX(a,2);
+ }
+
+ if ( FLAGS_GET_M(flags) ) {
+ gbox->mmin = (double)GIDX_GET_MIN(a,3);
+ gbox->mmax = (double)GIDX_GET_MAX(a,3);
+ }
+}
+
+
/**
* Given a #GSERIALIZED datum, as quickly as possible (peaking into the top
* of the memory) return the gbox extents. Does not deserialize the geometry,
if( LW_FAILURE == gserialized_datum_get_gidx_p(gsdatum, gidx) )
return LW_FAILURE;
- gbox_from_gidx(gidx, gbox);
gbox->flags = gserialized_datum_get_flags(gsdatum);
+ gbox_from_gidx(gidx, gbox, gbox->flags);
return LW_SUCCESS;
}
*/
GSERIALIZED* gserialized_set_gidx(GSERIALIZED *g, GIDX *gidx)
{
- int g_ndims = (FLAGS_GET_GEODETIC(g->flags) ? 3 : FLAGS_NDIMS(g->flags));
+ int g_ndims = FLAGS_NDIMS_BOX(g->flags);
int box_ndims = GIDX_NDIMS(gidx);
GSERIALIZED *g_out = NULL;
size_t box_size = 2 * g_ndims * sizeof(float);
*/
GSERIALIZED* gserialized_drop_gidx(GSERIALIZED *g)
{
- int g_ndims = (FLAGS_GET_GEODETIC(g->flags) ? 3 : FLAGS_NDIMS(g->flags));
+ int g_ndims = FLAGS_NDIMS_BOX(g->flags);
size_t box_size = 2 * g_ndims * sizeof(float);
size_t g_out_size = VARSIZE(g) - box_size;
GSERIALIZED *g_out = palloc(g_out_size);
return g_out;
}
-
-/* Convert a double-based GBOX into a float-based GIDX,
- ensuring the float box is larger than the double box */
-static int gidx_from_gbox_p(GBOX box, GIDX *a)
-{
- int ndims;
-
- ndims = (FLAGS_GET_GEODETIC(box.flags) ? 3 : FLAGS_NDIMS(box.flags));
- SET_VARSIZE(a, VARHDRSZ + ndims * 2 * sizeof(float));
-
- GIDX_SET_MIN(a,0,next_float_down(box.xmin));
- GIDX_SET_MAX(a,0,next_float_up(box.xmax));
- GIDX_SET_MIN(a,1,next_float_down(box.ymin));
- GIDX_SET_MAX(a,1,next_float_up(box.ymax));
-
- /* Geodetic indexes are always 3d, geocentric x/y/z */
- if ( FLAGS_GET_GEODETIC(box.flags) )
- {
- GIDX_SET_MIN(a,2,next_float_down(box.zmin));
- GIDX_SET_MAX(a,2,next_float_up(box.zmax));
- }
- else
- {
- /* Cartesian with Z implies Z is third dimension */
- if ( FLAGS_GET_Z(box.flags) )
- {
- GIDX_SET_MIN(a,2,next_float_down(box.zmin));
- GIDX_SET_MAX(a,2,next_float_up(box.zmax));
- if ( FLAGS_GET_M(box.flags) )
- {
- GIDX_SET_MIN(a,3,next_float_down(box.mmin));
- GIDX_SET_MAX(a,3,next_float_up(box.mmax));
- }
- }
- /* Unless there's no Z, in which case M is third dimension */
- else if ( FLAGS_GET_M(box.flags) )
- {
- GIDX_SET_MIN(a,2,next_float_down(box.mmin));
- GIDX_SET_MAX(a,2,next_float_up(box.mmax));
- }
- }
-
- POSTGIS_DEBUGF(5, "converted %s to %s", gbox_to_string(&box), gidx_to_string(a));
-
- return LW_SUCCESS;
-}
-
-
-GIDX* gidx_from_gbox(GBOX box)
-{
- int ndims;
- GIDX *a;
-
- ndims = (FLAGS_GET_GEODETIC(box.flags) ? 3 : FLAGS_NDIMS(box.flags));
- a = gidx_new(ndims);
- gidx_from_gbox_p(box, a);
- return a;
-}
-
-
-void gbox_from_gidx(GIDX *a, GBOX *gbox)
-{
- gbox->xmin = (double)GIDX_GET_MIN(a,0);
- gbox->ymin = (double)GIDX_GET_MIN(a,1);
- gbox->zmin = (double)GIDX_GET_MIN(a,2);
- gbox->xmax = (double)GIDX_GET_MAX(a,0);
- gbox->ymax = (double)GIDX_GET_MAX(a,1);
- gbox->zmax = (double)GIDX_GET_MAX(a,2);
-}
-
/**
* Peak into a #GSERIALIZED datum to find the bounding box. If the
* box is there, copy it out and return it. If not, calculate the box from the
if ( FLAGS_GET_BBOX(gpart->flags) )
{
/* Yes! Copy it out into the GIDX! */
- const size_t size = gbox_serialized_size(gpart->flags);
+ size_t size = gbox_serialized_size(gpart->flags);
POSTGIS_DEBUG(4, "copying box out of serialization");
memcpy(gidx->c, gpart->data, size);
+ /* if M is present but Z is not, pad Z and shift M */
+ if ( FLAGS_GET_M(gpart->flags) && ! FLAGS_GET_Z(gpart->flags) )
+ {
+ size += 2 * sizeof(float);
+ GIDX_SET_MIN(gidx,3,GIDX_GET_MIN(gidx,2));
+ GIDX_SET_MAX(gidx,3,GIDX_GET_MAX(gidx,2));
+ GIDX_SET_MIN(gidx,2,-1*FLT_MAX);
+ GIDX_SET_MAX(gidx,2,FLT_MAX);
+ }
SET_VARSIZE(gidx, VARHDRSZ + size);
result = LW_SUCCESS;
}
if ( FLAGS_GET_BBOX(g->flags) )
{
- int ndims = FLAGS_NDIMS_BOX(g->flags);
+ int ndims = FLAGS_NDIMS_GIDX(g->flags);
const size_t size = 2 * ndims * sizeof(float);
POSTGIS_DEBUG(4, "copying box out of serialization");
memcpy(gidx->c, g->data, size);
'POINT(2 4 2 4)'::geometry; -- t
select 'ndov7', 'LINESTRING(2 2 2 2, 4 4 4 4)'::geometry &&&
'POINT(4 2 4 2)'::geometry; -- t
--- TODO: mixed-dimension &&& overlap
+
+-- &&& with mixed dimensions
+
+WITH v(i,g) AS ( VALUES
+ (1,'POINT(0 0)'::geometry), -- true, infinite M range
+ (2,'POINTZ(0 0 1)'), -- true, infinite M range
+ (3,'POINTZ(0 0 0)'), -- true, infinite M range
+ (4,'POINTM(0 0 1)'), -- true, fully defined overlap
+ (5,'POINTZM(0 0 0 1)'), -- true, fully defined overlap
+ (6,'POINTZM(0 0 1 0)'), -- false, M out of range
+ (7,'LINESTRINGM(-1 0 2,1 0 3)'), -- false, M out of range
+ (8,'LINESTRINGZ(-1 0 2,1 0 3)') -- true, infinite M range
+ )
+SELECT 'ndovm1', array_agg(i) FROM v WHERE g &&& 'POINTM(0 0 1)'::geometry
+ORDER BY 1;
+
+WITH v(i,g) AS ( VALUES
+ (1,'POINT(0 0)'::geometry), -- true, infinite Z range
+ (2,'POINTZ(0 0 1)'), -- true, fully defined overlap
+ (3,'POINTZ(0 0 0)'), -- false, Z out of range
+ (4,'POINTM(0 0 0)'), -- true, infinite Z range
+ (5,'POINTZM(0 0 0 1)'), -- false, Z out of range
+ (6,'POINTZM(0 0 1 0)'), -- true, fully defined overlap
+ (7,'LINESTRINGM(-1 0 2,1 0 3)'), -- true, infinite Z range
+ (8,'LINESTRINGZ(-1 0 2,1 0 3)') -- false, Z out of range
+ )
+SELECT 'ndovm2', array_agg(i) FROM v WHERE g &&& 'POINTZ(0 0 1)'::geometry
+ORDER BY 1;