Replace uncompressed filter hack with native GHT filtering for GHT cases.

This commit is contained in:
Paul Ramsey 2013-06-28 11:35:27 -07:00
parent 9e3354845e
commit b8ff674ac4
5 changed files with 175 additions and 24 deletions

View File

@ -43,7 +43,7 @@ test_patch_ght()
{
PCPOINT *pt;
int i;
int npts = 100;
static int npts = 100;
PCPOINTLIST *pl1, *pl2;
PCPATCH_GHT *pag;
PCPATCH_UNCOMPRESSED *pu;
@ -61,6 +61,8 @@ test_patch_ght()
}
pag = pc_patch_ght_from_pointlist(pl1);
pc_pointlist_free(pl1);
pu = pc_patch_uncompressed_from_ght(pag);
CU_ASSERT_EQUAL(npts, pag->npoints);
CU_ASSERT_EQUAL(npts, pu->npoints);
@ -83,7 +85,50 @@ test_patch_ght()
pc_patch_uncompressed_free(pu);
pc_patch_ght_free(pag);
}
static void
test_patch_ght_filtering()
{
int dimnum = 2; /* Z */
PCPOINT *pt;
int i;
static int npts = 100;
PCPOINTLIST *pl1, *pl2;
PCPATCH_GHT *pag, *pag_filtered;
pl1 = pc_pointlist_make(npts);
for ( i = 0; i < npts; i++ )
{
pt = pc_point_make(simpleschema);
pc_point_set_double_by_name(pt, "x", 45 + i*0.000004);
pc_point_set_double_by_name(pt, "y", 45 + i*0.000001666);
pc_point_set_double_by_name(pt, "Z", 10 + i*0.34);
pc_point_set_double_by_name(pt, "intensity", 10);
pc_pointlist_add_point(pl1, pt);
}
pag = pc_patch_ght_from_pointlist(pl1);
pc_pointlist_free(pl1);
pag_filtered = pc_patch_ght_filter(pag, dimnum, PC_LT, 10, 10);
CU_ASSERT_EQUAL(pag_filtered->npoints, 0);
pc_patch_ght_free(pag_filtered);
pag_filtered = pc_patch_ght_filter(pag, dimnum, PC_LT, 11, 11);
CU_ASSERT_EQUAL(pag_filtered->npoints, 3);
pc_patch_ght_free(pag_filtered);
pag_filtered = pc_patch_ght_filter(pag, dimnum, PC_GT, 11, 11);
CU_ASSERT_EQUAL(pag_filtered->npoints, 97);
pc_patch_ght_free(pag_filtered);
pag_filtered = pc_patch_ght_filter(pag, dimnum, PC_BETWEEN, 11, 16);
CU_ASSERT_EQUAL(pag_filtered->npoints, 15);
pc_patch_ght_free(pag_filtered);
pc_patch_ght_free(pag);
}
@ -94,6 +139,7 @@ test_patch_ght()
CU_TestInfo ght_tests[] = {
#ifdef HAVE_LIBGHT
PC_TEST(test_patch_ght),
PC_TEST(test_patch_ght_filtering),
#endif
CU_TEST_INFO_NULL
};

View File

@ -189,7 +189,7 @@ int pc_patch_ght_compute_extent(PCPATCH_GHT *patch);
uint8_t* pc_patch_ght_to_wkb(const PCPATCH_GHT *patch, size_t *wkbsize);
PCPATCH* pc_patch_ght_from_wkb(const PCSCHEMA *schema, const uint8_t *wkb, size_t wkbsize);
PCPOINTLIST* pc_pointlist_from_ght(const PCPATCH_GHT *pag);
PCPATCH_GHT* pc_patch_ght_filter(const PCPATCH_GHT *patch, uint32_t dimnum, PC_FILTERTYPE filter, double val1, double val2);
/****************************************************************************

View File

@ -178,25 +178,18 @@ pc_patch_filter(const PCPATCH *pa, uint32_t dimnum, PC_FILTERTYPE filter, double
}
pu = pc_patch_uncompressed_filter((PCPATCH_UNCOMPRESSED*)pa, map);
pc_bitmap_free(map);
/* pc_patch_uncompressed_filter computes stats and bounds, so we're ready to return here */
/* TODO, it could/should compute bounds and stats while filtering the points */
paout = (PCPATCH*)pu;
break;
}
case PC_GHT:
{
PCPATCH_UNCOMPRESSED *pu = pc_patch_uncompressed_from_ght((PCPATCH_GHT*)pa);
PCBITMAP *map = pc_patch_uncompressed_bitmap(pu, dimnum, filter, val1, val2);
PCPATCH_UNCOMPRESSED *pu2;
PCPATCH_GHT *pgh;
if ( map->nset == 0 )
{
pc_bitmap_free(map);
return (PCPATCH*)pc_patch_uncompressed_make(pa->schema, 0);
}
pu2 = pc_patch_uncompressed_filter(pu, map);
pgh = pc_patch_ght_from_uncompressed(pu2);
pc_patch_free((PCPATCH*)pu);
pc_patch_free((PCPATCH*)pu2);
paout = (PCPATCH*)pgh;
PCPATCH_GHT *pgh = pc_patch_ght_filter((PCPATCH_GHT*)pa, dimnum, filter, val1, val2);
/* pc_patch_ght_filter computes the bounds itself */
/* TODO: add stats computation to pc_patch_ght_filter */
/* pc_patch_ght_filter is just re-using the input stats, which is wrong */
paout = (PCPATCH*)pgh;
break;
}
case PC_DIMENSIONAL:
@ -211,18 +204,21 @@ pc_patch_filter(const PCPATCH *pa, uint32_t dimnum, PC_FILTERTYPE filter, double
pdl = pc_patch_dimensional_filter((PCPATCH_DIMENSIONAL*)pa, map);
pc_bitmap_free(map);
paout = (PCPATCH*)pdl;
/* pc_patch_dimensional_filter does not compute computes stats or bounds, so we need to do it here */
/* TODO: this is expensive, we should do this while we are traversing the bytes in the filter process */
if ( PC_FAILURE == pc_patch_compute_extent(paout) )
pcerror("%s: pc_patch_compute_extent failed", __func__);
if ( PC_FAILURE == pc_patch_compute_stats(paout) )
pcerror("%s: pc_patch_compute_stats failed", __func__);
break;
}
default:
pcerror("%s: failure", __func__);
}
if ( PC_FAILURE == pc_patch_compute_extent(paout) )
pcerror("%s: pc_patch_compute_extent failed", __func__);
if ( PC_FAILURE == pc_patch_compute_stats(paout) )
pcerror("%s: pc_patch_compute_stats failed", __func__);
return paout;
}

View File

@ -424,9 +424,9 @@ pc_patch_ght_compute_extent(PCPATCH_GHT *patch)
return PC_FAILURE;
patch->bounds.xmin = area.x.min;
patch->bounds.xmax = area.x.min;
patch->bounds.xmax = area.x.max;
patch->bounds.ymin = area.y.min;
patch->bounds.ymax = area.y.min;
patch->bounds.ymax = area.y.max;
ght_tree_free(tree);
@ -487,6 +487,114 @@ pc_patch_ght_to_wkb(const PCPATCH_GHT *patch, size_t *wkbsize)
#endif
}
PCPATCH_GHT *
pc_patch_ght_filter(const PCPATCH_GHT *patch, uint32_t dimnum, PC_FILTERTYPE filter, double val1, double val2)
{
#ifndef HAVE_LIBGHT
pcerror("%s: libght support is not enabled", __func__);
return NULL;
#else
/*
byte: endianness (1 = NDR, 0 = XDR)
uint32: pcid (key to POINTCLOUD_SCHEMAS)
uint32: compression (0 = no compression, 1 = dimensional, 2 = GHT)
uint32: npoints
uint32: ghtsize
uint8[]: ghtbuffer
*/
GhtTreePtr tree;
GhtTreePtr tree_filtered;
GhtErr err;
GhtWriterPtr writer;
GhtArea area;
const char *dimname;
const PCDIMENSION *dim;
PCPATCH_GHT *paght;
int npoints;
/* Echo null back */
if ( ! patch ) return NULL;
/* Get a tree */
tree = ght_tree_from_pc_patch(patch);
if ( ! tree ) pcerror("%s: call to ght_tree_from_pc_patch failed", __func__);
/* Get dimname */
dim = pc_schema_get_dimension(patch->schema, dimnum);
if ( ! dim ) pcerror("%s: invalid dimension number (%d)", __func__, dimnum);
dimname = dim->name;
switch ( filter )
{
case PC_GT:
err = ght_tree_filter_greater_than(tree, dimname, val1 > val2 ? val1 : val2, &tree_filtered);
break;
case PC_LT:
err = ght_tree_filter_less_than(tree, dimname, val1 < val2 ? val1 : val2, &tree_filtered);
break;
case PC_EQUAL:
err = ght_tree_filter_equal(tree, dimname, val1, &tree_filtered);
break;
case PC_BETWEEN:
err = ght_tree_filter_between(tree, dimname, val1, val2, &tree_filtered);
break;
default:
pcerror("%s: invalid filter type (%d)", __func__, filter);
}
/* ght_tree_filter_* returns a tree with NULL tree element and npoints == 0 */
/* for empty filter results (everything got filtered away) */
if ( err != GHT_OK || ! tree_filtered )
pcerror("%s: ght_tree_filter failed", __func__);
/* Read numpoints left in patch */
ght_tree_get_numpoints(tree_filtered, &(npoints));
/* Allocate a fresh GHT patch for output */
paght = pcalloc(sizeof(PCPATCH_GHT));
paght->type = PC_GHT;
paght->readonly = PC_FALSE;
paght->schema = patch->schema;
paght->npoints = npoints;
/* No points, not much to do... */
if ( ! npoints )
{
paght->ghtsize = 0;
paght->ght = NULL;
}
else
{
/* Calculate bounds and save */
if ( GHT_OK != ght_tree_get_extent(tree_filtered, &area) )
pcerror("%s: ght_tree_get_extent failed", __func__);
paght->bounds.xmin = area.x.min;
paght->bounds.xmax = area.x.max;
paght->bounds.ymin = area.y.min;
paght->bounds.ymax = area.y.max;
/* TODO: Replace this; need to update stats too */
paght->stats = pc_stats_clone(patch->stats);
/* Convert the tree to a memory buffer */
ght_writer_new_mem(&writer);
ght_tree_write(tree_filtered, writer);
ght_writer_get_size(writer, &(paght->ghtsize));
paght->ght = pcalloc(paght->ghtsize);
ght_writer_get_bytes(writer, paght->ght);
ght_writer_free(writer);
}
ght_tree_free(tree_filtered);
ght_tree_free(tree);
return paght;
#endif
}
PCPOINTLIST *
pc_pointlist_from_ght(const PCPATCH_GHT *pag)

View File

@ -685,6 +685,7 @@ Datum pcpatch_filter(PG_FUNCTION_ARGS)
}
pfree(dim_name);
/* Always treat zero-point patches as SQL NULL */
if ( patch_filtered->npoints <= 0 )
{
pc_patch_free(patch_filtered);