mirror of
https://github.com/pgpointcloud/pointcloud.git
synced 2025-12-08 20:36:04 +00:00
Replace uncompressed filter hack with native GHT filtering for GHT cases.
This commit is contained in:
parent
9e3354845e
commit
b8ff674ac4
@ -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
|
||||
};
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user