Add PC_Range(p PCPATCH, first int4, count int4)

This commit adds a PC_Range function. This function returns a patch of "count" points. These points are selected from the start-th point in the input patch.
This commit is contained in:
Blottiere Paul 2016-08-05 14:35:32 +02:00 committed by Éric Lemoine
parent da831e50b6
commit fb5f1dcca4
9 changed files with 350 additions and 4 deletions

1
NEWS
View File

@ -10,6 +10,7 @@
- PC_Lib_Version(), PC_Script_Version() (#40)
- PC_Sort(pcpatch,text[]) (#106)
- PC_IsSorted(pcpatch,text[],boolean) (#106)
- PC_Range(pcpatch, int, int) returns pcpatch (#152)
- Enhancements
- Support sigbits encoding for 64bit integers (#61)
- Warn about truncated values (#68)

View File

@ -471,6 +471,9 @@ Now that you have created two tables, you'll see entries for them in the `pointc
> Returns a copy of the input patch lexicographically sorted along the given dimensions.
**PC_Range(p pcpatch, start int4, n int4)** returns **pcpatch**
> Returns a patch containing *n* points. These points are selected from the *start*-th point with 1-based indexing.
## PostGIS Integration ##

View File

@ -1,7 +1,7 @@
/***********************************************************************
* cu_pc_schema.c
*
* Testing for the schema API functions
* Testing for the schema API functions
*
* Portions Copyright (c) 2012, OpenGeo
*
@ -594,7 +594,7 @@ test_patch_compress_from_ght_to_lazperf()
pc_patch_free((PCPATCH *)patch_ght);
pc_patch_free((PCPATCH *)patch_lazperf);
}
#endif /* defined(HAVE_LIBGHT) && defined(HAVE_LAZPERF) */
#endif /* defined(HAVE_LIBGHT) && defined(HAVE_LAZPERF) */
static void
test_patch_pointn_last_first()
@ -765,6 +765,232 @@ test_patch_pointn_ght_compression()
pc_pointlist_free(li);
}
static void
test_patch_range_compression_none()
{
int i;
int npts = 20;
PCPOINTLIST *pl;
PCPATCH *pa;
PCPATCH *par;
char *str;
pl = pc_pointlist_make(npts);
for ( i = 0; i < npts; i++ )
{
PCPOINT *pt = pc_point_make(simpleschema);
pc_point_set_double_by_name(pt, "X", i);
pc_point_set_double_by_name(pt, "Y", i);
pc_point_set_double_by_name(pt, "Z", i * 0.1);
pc_point_set_double_by_name(pt, "Intensity", 100 - i);
pc_pointlist_add_point(pl, pt);
}
pa = (PCPATCH*)pc_patch_uncompressed_from_pointlist(pl);
par = pc_patch_range(pa, 16, 4);
str = pc_patch_to_string(par);
CU_ASSERT_STRING_EQUAL(str,
"{\"pcid\":0,\"pts\":[[15,15,1.5,85],[16,16,1.6,84],[17,17,1.7,83],[18,18,1.8,82]]}");
pcfree(str);
pc_patch_free(par);
pc_patch_free(pa);
pc_pointlist_free(pl);
}
static void
test_patch_range_compression_none_with_full_range()
{
int i;
int npts = 4;
PCPOINTLIST *pl;
PCPATCH *pa;
PCPATCH *par;
char *str;
pl = pc_pointlist_make(npts);
for ( i = 0; i < npts; i++ )
{
PCPOINT *pt = pc_point_make(simpleschema);
pc_point_set_double_by_name(pt, "X", i);
pc_point_set_double_by_name(pt, "Y", i);
pc_point_set_double_by_name(pt, "Z", i * 0.1);
pc_point_set_double_by_name(pt, "Intensity", 100 - i);
pc_pointlist_add_point(pl, pt);
}
pa = (PCPATCH*)pc_patch_uncompressed_from_pointlist(pl);
par = pc_patch_range(pa, 1, npts);
CU_ASSERT(pa == par);
str = pc_patch_to_string(par);
CU_ASSERT_STRING_EQUAL(str,
"{\"pcid\":0,\"pts\":[[0,0,0,100],[1,1,0.1,99],[2,2,0.2,98],[3,3,0.3,97]]}");
pcfree(str);
pc_patch_free(pa);
pc_pointlist_free(pl);
}
static void
test_patch_range_compression_none_with_bad_arguments(int first, int count)
{
int i;
int npts = 20;
PCPOINTLIST *pl;
PCPATCH *pa;
PCPATCH *par;
pl = pc_pointlist_make(npts);
for ( i = 0; i < npts; i++ )
{
PCPOINT *pt = pc_point_make(simpleschema);
pc_point_set_double_by_name(pt, "X", i);
pc_point_set_double_by_name(pt, "Y", i);
pc_point_set_double_by_name(pt, "Z", i * 0.1);
pc_point_set_double_by_name(pt, "Intensity", 100 - i);
pc_pointlist_add_point(pl, pt);
}
pa = (PCPATCH*)pc_patch_uncompressed_from_pointlist(pl);
par = pc_patch_range(pa, first, count);
CU_ASSERT(par == NULL);
pc_patch_free(pa);
pc_pointlist_free(pl);
}
static void
test_patch_range_compression_none_with_zero_count()
{
test_patch_range_compression_none_with_bad_arguments(1, 0);
}
static void
test_patch_range_compression_none_with_zero_first()
{
test_patch_range_compression_none_with_bad_arguments(0, 1);
}
static void
test_patch_range_compression_none_with_out_of_bounds_first()
{
test_patch_range_compression_none_with_bad_arguments(21, 1);
}
static void
test_patch_range_compression_lazperf()
{
int i;
int npts = 20;
PCPOINTLIST *pl;
PCPATCH *pa;
PCPATCH *par;
char *str;
pl = pc_pointlist_make(npts);
for ( i = 0; i < npts; i++ )
{
PCPOINT *pt = pc_point_make(simpleschema);
pc_point_set_double_by_name(pt, "X", i);
pc_point_set_double_by_name(pt, "Y", i);
pc_point_set_double_by_name(pt, "Z", i * 0.1);
pc_point_set_double_by_name(pt, "Intensity", 100 - i);
pc_pointlist_add_point(pl, pt);
}
pa = (PCPATCH*)pc_patch_lazperf_from_pointlist(pl);
par = pc_patch_range(pa, 16, 4);
str = pc_patch_to_string(par);
CU_ASSERT_STRING_EQUAL(str,
"{\"pcid\":0,\"pts\":[[15,15,1.5,85],[16,16,1.6,84],[17,17,1.7,83],[18,18,1.8,82]]}");
pcfree(str);
pc_patch_free(par);
pc_patch_free(pa);
pc_pointlist_free(pl);
}
static void
test_patch_range_compression_dimensional(enum DIMCOMPRESSIONS dimcomp)
{
int i;
PCPOINTLIST *pl;
PCPATCH *pa;
PCPATCH *par;
PCPATCH_DIMENSIONAL *pad;
PCPOINT *pt;
char *str;
int npts = PCDIMSTATS_MIN_SAMPLE+1; // force to keep custom compression
// build a dimensional patch
pl = pc_pointlist_make(npts);
for ( i = npts; i >= 0; i-- )
{
pt = pc_point_make(simpleschema);
pc_point_set_double_by_name(pt, "X", i);
pc_point_set_double_by_name(pt, "Y", i);
pc_point_set_double_by_name(pt, "Z", i);
pc_point_set_double_by_name(pt, "Intensity", 10);
pc_pointlist_add_point(pl, pt);
}
pad = pc_patch_dimensional_from_pointlist(pl);
// set dimensional compression for each dimension
PCDIMSTATS *stats = pc_dimstats_make(simpleschema);
pc_dimstats_update(stats, pad);
for ( i = 0; i<pad->schema->ndims; i++ )
stats->stats[i].recommended_compression = dimcomp;
// compress patch
pa = (PCPATCH*) pc_patch_dimensional_compress(pad, stats);
par = pc_patch_range(pa, 16, 4);
str = pc_patch_to_string(par);
CU_ASSERT_STRING_EQUAL(str,
"{\"pcid\":0,\"pts\":[[9986,9986,9986,10],[9985,9985,9985,10],[9984,9984,9984,10],[9983,9983,9983,10]]}");
pcfree(str);
pc_patch_free(par);
pc_patch_free((PCPATCH *)pad);
pc_dimstats_free(stats);
pc_patch_free(pa);
pc_pointlist_free(pl);
}
static void
test_patch_range_compression_dimensional_none()
{
test_patch_range_compression_dimensional(PC_DIM_NONE);
}
static void
test_patch_range_compression_dimensional_zlib()
{
test_patch_range_compression_dimensional(PC_DIM_ZLIB);
}
static void
test_patch_range_compression_dimensional_sigbits()
{
test_patch_range_compression_dimensional(PC_DIM_SIGBITS);
}
static void
test_patch_range_compression_dimensional_rle()
{
test_patch_range_compression_dimensional(PC_DIM_RLE);
}
/* REGISTER ***********************************************************/
CU_TestInfo patch_tests[] = {
@ -788,6 +1014,18 @@ CU_TestInfo patch_tests[] = {
PC_TEST(test_patch_pointn_dimensional_compression_sigbits),
PC_TEST(test_patch_pointn_dimensional_compression_rle),
PC_TEST(test_patch_pointn_ght_compression),
PC_TEST(test_patch_range_compression_none),
PC_TEST(test_patch_range_compression_none_with_full_range),
PC_TEST(test_patch_range_compression_none_with_zero_count),
PC_TEST(test_patch_range_compression_none_with_zero_first),
PC_TEST(test_patch_range_compression_none_with_out_of_bounds_first),
PC_TEST(test_patch_range_compression_dimensional_none),
PC_TEST(test_patch_range_compression_dimensional_zlib),
PC_TEST(test_patch_range_compression_dimensional_sigbits),
PC_TEST(test_patch_range_compression_dimensional_rle),
#ifdef HAVE_LAZPERF
PC_TEST(test_patch_range_compression_lazperf),
#endif
CU_TEST_INFO_NULL
};

View File

@ -458,4 +458,7 @@ PCPATCH *pc_patch_sort(const PCPATCH *pa, const char **name, int ndims);
/** True/false if the patch is sorted on dimension */
uint32_t pc_patch_is_sorted(const PCPATCH *pa, const char **name, int ndims, char strict);
/** Subset batch based on index */
PCPATCH* pc_patch_range(const PCPATCH *pa, int first, int count);
#endif /* _PC_API_H */

View File

@ -306,7 +306,7 @@ PCPATCH *
pc_patch_from_wkb(const PCSCHEMA *s, uint8_t *wkb, size_t wkbsize)
{
/*
byte: endianness (1 = NDR, 0 = XDR)
byte: endianness (1 = NDR, 0 = XDR)
uint32: pcid (key to POINTCLOUD_SCHEMAS)
uint32: compression (0 = no compression, 1 = dimensional, 2 = GHT)
uchar[]: data (interpret relative to pcid and compression)
@ -378,7 +378,7 @@ uint8_t *
pc_patch_to_wkb(const PCPATCH *patch, size_t *wkbsize)
{
/*
byte: endianness (1 = NDR, 0 = XDR)
byte: endianness (1 = NDR, 0 = XDR)
uint32: pcid (key to POINTCLOUD_SCHEMAS)
uint32: compression (0 = no compression, 1 = dimensional, 2 = GHT)
uchar[]: data (interpret relative to pcid and compression)
@ -522,6 +522,68 @@ pc_patch_from_patchlist(PCPATCH **palist, int numpatches)
return (PCPATCH*)paout;
}
// first: the first element to select (1-based indexing)
// count: the number of points to select
PCPATCH *
pc_patch_range(const PCPATCH *pa, int first, int count)
{
PCPATCH_UNCOMPRESSED *paout, *pu;
int countmax;
uint8_t *buf;
size_t size;
size_t start;
assert(pa);
first--;
countmax = pa->npoints - first;
if ( count > countmax )
count = countmax;
if ( first < 0 || count <= 0 )
return NULL;
if ( count == pa->npoints )
return (PCPATCH *) pa;
paout = pc_patch_uncompressed_make(pa->schema, count);
if ( !paout )
return NULL;
paout->npoints = count;
pu = (PCPATCH_UNCOMPRESSED *) pc_patch_uncompress(pa);
if ( !pu )
{
pc_patch_free((PCPATCH *) paout);
return NULL;
}
buf = paout->data;
start = pa->schema->size * first;
size = pa->schema->size * count;
memcpy(buf, pu->data + start, size);
if ( ((PCPATCH *) pu) != pa )
pc_patch_free((PCPATCH *) pu);
if ( PC_FAILURE == pc_patch_uncompressed_compute_extent(paout) )
{
pcerror("%s: extent computation failed", __func__);
pc_patch_free((PCPATCH *) paout);
return NULL;
}
if ( PC_FAILURE == pc_patch_uncompressed_compute_stats(paout) )
{
pcerror("%s: stats computation failed", __func__);
pc_patch_free((PCPATCH *) paout);
return NULL;
}
return (PCPATCH *) paout;
}
/** get point n from patch */
/** positive 1-based: 1=first point, npoints=last point */
/** negative 1-based: -1=last point, -npoints=first point */

View File

@ -312,6 +312,15 @@ SELECT sum(PC_NumPoints(pa)) FROM pa_test;
8
(1 row)
SELECT PC_AsText(PC_Range(pa, 1, 1)) FROM pa_test;
pc_astext
---------------------------------------
{"pcid":1,"pts":[[0.02,0.03,0.05,6]]}
{"pcid":1,"pts":[[0.06,0.07,0.05,6]]}
{"pcid":1,"pts":[[0.06,0.07,0.05,6]]}
{"pcid":1,"pts":[[0.06,0.07,0.05,6]]}
(4 rows)
CREATE TABLE IF NOT EXISTS pa_test_dim (
pa PCPATCH(3)
);

View File

@ -28,6 +28,7 @@ Datum pcpatch_uncompress(PG_FUNCTION_ARGS);
Datum pcpatch_compress(PG_FUNCTION_ARGS);
Datum pcpatch_numpoints(PG_FUNCTION_ARGS);
Datum pcpatch_pointn(PG_FUNCTION_ARGS);
Datum pcpatch_range(PG_FUNCTION_ARGS);
Datum pcpatch_pcid(PG_FUNCTION_ARGS);
Datum pcpatch_summary(PG_FUNCTION_ARGS);
Datum pcpatch_compression(PG_FUNCTION_ARGS);
@ -677,6 +678,29 @@ Datum pcpatch_pointn(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(serpt);
}
PG_FUNCTION_INFO_V1(pcpatch_range);
Datum pcpatch_range(PG_FUNCTION_ARGS)
{
SERIALIZED_PATCH *serpaout;
SERIALIZED_PATCH *serpa = PG_GETARG_SERPATCH_P(0);
int32 first = PG_GETARG_INT32(1);
int32 count = PG_GETARG_INT32(2);
PCSCHEMA *schema = pc_schema_from_pcid(serpa->pcid, fcinfo);
PCPATCH *patch = pc_patch_deserialize(serpa, schema);
PCPATCH *patchout = NULL;
if ( patch )
{
patchout = pc_patch_range(patch, first, count);
if ( patchout != patch )
pc_patch_free(patch);
}
if ( !patchout )
PG_RETURN_NULL();
serpaout = pc_patch_serialize(patchout, NULL);
pc_patch_free(patchout);
PG_RETURN_POINTER(serpaout);
}
PG_FUNCTION_INFO_V1(pcpatch_pcid);
Datum pcpatch_pcid(PG_FUNCTION_ARGS)
{

View File

@ -309,6 +309,10 @@ CREATE OR REPLACE FUNCTION PC_IsSorted(p pcpatch, attr text[], strict boolean de
RETURNS boolean AS 'MODULE_PATHNAME', 'pcpatch_is_sorted'
LANGUAGE 'c' IMMUTABLE STRICT;
CREATE OR REPLACE FUNCTION PC_Range(p pcpatch, first int4, count int4)
RETURNS pcpatch AS 'MODULE_PATHNAME', 'pcpatch_range'
LANGUAGE 'c' IMMUTABLE STRICT;
-------------------------------------------------------------------
-- POINTCLOUD_COLUMNS
-------------------------------------------------------------------

View File

@ -232,6 +232,8 @@ SELECT PC_Envelope(pa) from pa_test;
SELECT PC_AsText(PC_Union(pa)) FROM pa_test;
SELECT sum(PC_NumPoints(pa)) FROM pa_test;
SELECT PC_AsText(PC_Range(pa, 1, 1)) FROM pa_test;
CREATE TABLE IF NOT EXISTS pa_test_dim (
pa PCPATCH(3)
);