Finish implementation of patch-level stats

This commit is contained in:
Paul Ramsey 2013-05-31 15:36:23 -07:00
parent 89611f6101
commit 8174fa4ca3
8 changed files with 115 additions and 49 deletions

View File

@ -111,11 +111,19 @@ test_patch_hex_in()
uint8_t *wkb = bytes_from_hexbytes(hexbuf, hexsize);
PCPATCH *pa = pc_patch_from_wkb(simpleschema, wkb, hexsize/2);
PCPOINTLIST *pl = pc_pointlist_from_patch(pa);
pc_point_get_double_by_name(pc_pointlist_get_point(pl, 0), "X", &d);
CU_ASSERT_DOUBLE_EQUAL(d, 0.02, 0.000001);
pc_point_get_double_by_name(pc_pointlist_get_point(pl, 1), "Intensity", &d);
CU_ASSERT_DOUBLE_EQUAL(d, 8, 0.000001);
pc_point_get_double_by_name(&(pa->stats->min), "Intensity", &d);
CU_ASSERT_DOUBLE_EQUAL(d, 6, 0.000001);
pc_point_get_double_by_name(&(pa->stats->max), "Intensity", &d);
CU_ASSERT_DOUBLE_EQUAL(d, 8, 0.000001);
pc_point_get_double_by_name(&(pa->stats->avg), "Intensity", &d);
CU_ASSERT_DOUBLE_EQUAL(d, 7, 0.000001);
str = pc_patch_to_string(pa);
CU_ASSERT_STRING_EQUAL(str, "{\"pcid\":0,\"pts\":[[0.02,0.03,0.05,6],[0.02,0.03,0.05,8]]}");
// printf("\n%s\n",str);

View File

@ -142,8 +142,8 @@ typedef struct
/* Used for generic patch statistics */
typedef struct
{
PCPOINT max;
PCPOINT min;
PCPOINT max;
PCPOINT avg;
}
PCSTATS;
@ -263,6 +263,8 @@ PCSCHEMA* pc_schema_clone(const PCSCHEMA *s);
void pc_schema_set_dimension(PCSCHEMA *s, PCDIMENSION *d);
/** Check/set the x/y position in the dimension list */
void pc_schema_check_xy(PCSCHEMA *s);
/** Get the width in bytes of a single point in the schema */
size_t pc_schema_get_size(const PCSCHEMA *s);
/**********************************************************************
@ -376,7 +378,10 @@ int pc_bytes_serialize(const PCBYTES *pcb, uint8_t *buf, size_t *size);
int pc_bytes_deserialize(const uint8_t *buf, const PCDIMENSION *dim, PCBYTES *pcb, int readonly, int flip_endian);
/** Wrap serialized stats in a new stats objects */
PCSTATS* pc_stats_new_from_data(const PCSCHEMA *schema, const uint8_t *mindata, const uint8_t *maxdata, const uint8_t *avgdata);\
PCSTATS* pc_stats_new_from_data(const PCSCHEMA *schema, const uint8_t *mindata, const uint8_t *maxdata, const uint8_t *avgdata);
/** Free a stats object */
void pc_stats_free(PCSTATS *stats);
/** Calculate stats from an existing patch */
int pc_patch_compute_stats(PCPATCH *patch);

View File

@ -599,3 +599,9 @@ pc_schema_get_dimension_by_name(const PCSCHEMA *s, const char *name)
return hashtable_search(s->namehash, name);
}
size_t
pc_schema_get_size(const PCSCHEMA *s)
{
return s->size;
}

View File

@ -2,7 +2,7 @@ CREATE EXTENSION pointcloud;
SELECT PC_Version();
pc_version
------------
1.0
0.1
(1 row)
INSERT INTO pointcloud_formats (pcid, srid, schema)
@ -272,7 +272,7 @@ SELECT Sum(PC_NumPoints(pa)) FROM pa_test_dim;
SELECT Sum(PC_MemSize(pa)) FROM pa_test_dim;
sum
-----
516
684
(1 row)
SELECT Sum(PC_PatchMax(pa,'x')) FROM pa_test_dim;
@ -308,7 +308,7 @@ SELECT Sum(PC_NumPoints(pa)) FROM pa_test_dim;
SELECT Sum(PC_MemSize(pa)) FROM pa_test_dim;
sum
------
8523
8733
(1 row)
SELECT Max(PC_PatchMax(pa,'x')) FROM pa_test_dim;
@ -351,7 +351,7 @@ SELECT Sum(PC_NumPoints(pa)) FROM pa_test_ght;
SELECT Sum(PC_MemSize(pa)) FROM pa_test_ght;
sum
-----
420
588
(1 row)
SELECT Sum(PC_PatchMax(pa,'x')) FROM pa_test_ght;
@ -387,7 +387,7 @@ SELECT Sum(PC_NumPoints(pa)) FROM pa_test_ght;
SELECT Sum(PC_MemSize(pa)) FROM pa_test_ght;
sum
-------
38471
38681
(1 row)
SELECT Max(PC_PatchMax(pa,'x')) FROM pa_test_ght;

View File

@ -21,6 +21,7 @@ Datum pcpatch_uncompress(PG_FUNCTION_ARGS);
Datum pcpatch_numpoints(PG_FUNCTION_ARGS);
Datum pcpatch_compression(PG_FUNCTION_ARGS);
Datum pcpatch_intersects(PG_FUNCTION_ARGS);
Datum pcpatch_get_stat(PG_FUNCTION_ARGS);
Datum pcpatch_size(PG_FUNCTION_ARGS);
Datum pcpoint_size(PG_FUNCTION_ARGS);
Datum pc_version(PG_FUNCTION_ARGS);
@ -582,3 +583,53 @@ Datum pc_version(PG_FUNCTION_ARGS)
PG_RETURN_TEXT_P(version_text);
}
/**
* Read a named dimension statistic from a PCPATCH
* PC_PatchMax(patch pcpatch, dimname text) returns Numeric
* PC_PatchMin(patch pcpatch, dimname text) returns Numeric
* PC_PatchAvg(patch pcpatch, dimname text) returns Numeric
*/
PG_FUNCTION_INFO_V1(pcpatch_get_stat);
Datum pcpatch_get_stat(PG_FUNCTION_ARGS)
{
static int stats_size_guess = 400;
SERIALIZED_PATCH *serpa = PG_GETHEADERX_SERPATCH_P(0, stats_size_guess);
PCSCHEMA *schema = pc_schema_from_pcid(serpa->pcid, fcinfo);
char *dim_str = text_to_cstring(PG_GETARG_TEXT_P(1));
char *stat_str = text_to_cstring(PG_GETARG_TEXT_P(2));
PCSTATS *stats;
float8 double_result;
int rv;
if ( stats_size_guess < 3*schema->size )
{
serpa = PG_GETHEADERX_SERPATCH_P(0, 3*schema->size);
}
stats = pc_patch_stats_deserialize(schema, serpa->data);
if ( ! stats )
PG_RETURN_NULL();
/* Max */
if ( 0 == strcasecmp("max", stat_str) )
rv = pc_point_get_double_by_name(&(stats->max), dim_str, &double_result);
/* Min */
else if ( 0 == strcasecmp("min", stat_str) )
rv = pc_point_get_double_by_name(&(stats->min), dim_str, &double_result);
/* Avg */
else if ( 0 == strcasecmp("avg", stat_str) )
rv = pc_point_get_double_by_name(&(stats->avg), dim_str, &double_result);
/* Unsupported */
else
elog(ERROR, "stat type \"%s\" is not supported", stat_str);
pfree(stat_str);
pc_stats_free(stats);
if ( ! rv )
elog(ERROR, "dimension \"%s\" does not exist in schema", dim_str);
pfree(dim_str);
PG_RETURN_DATUM(DirectFunctionCall1(float8_numeric, Float8GetDatum(double_result)));
}

View File

@ -471,24 +471,18 @@ pc_patch_serialized_size(const PCPATCH *patch)
return -1;
}
static uint8_t *
static size_t
pc_patch_stats_serialize(uint8_t *buf, const PCSCHEMA *schema, const PCSTATS *stats)
{
size_t sz = schema->size;
/* Copy min */
memcpy(buf, stats->min.data, sz);
buf += sz;
/* Copy max */
memcpy(buf, stats->max.data, sz);
buf += sz;
memcpy(buf + sz, stats->max.data, sz);
/* Copy avg */
memcpy(buf, stats->avg.data, sz);
buf += sz;
return buf;
memcpy(buf + 2*sz, stats->avg.data, sz);
return sz*3;
}
/**
@ -496,7 +490,7 @@ pc_patch_stats_serialize(uint8_t *buf, const PCSCHEMA *schema, const PCSTATS *st
* min, max, avg. Their size is the uncompressed buffer size for
* a point, the schema->size.
*/
static PCSTATS *
PCSTATS *
pc_patch_stats_deserialize(const PCSCHEMA *schema, const uint8_t *buf)
{
size_t sz = schema->size;
@ -540,7 +534,7 @@ pc_patch_dimensional_serialize(const PCPATCH *patch_in)
/* Write stats into the buffer */
if ( patch->stats )
{
buf = pc_patch_stats_serialize(buf, patch->schema, patch->stats);
buf += pc_patch_stats_serialize(buf, patch->schema, patch->stats);
}
else
{
@ -592,7 +586,7 @@ pc_patch_ght_serialize(const PCPATCH *patch_in)
/* Write stats into the buffer first */
if ( patch->stats )
{
buf = pc_patch_stats_serialize(buf, patch->schema, patch->stats);
buf += pc_patch_stats_serialize(buf, patch->schema, patch->stats);
}
else
{
@ -638,7 +632,7 @@ pc_patch_uncompressed_serialize(const PCPATCH *patch_in)
buf = serpch->data;
if ( patch->stats )
{
buf = pc_patch_stats_serialize(buf, patch->schema, patch->stats);
buf += pc_patch_stats_serialize(buf, patch->schema, patch->stats);
}
else
{
@ -753,18 +747,9 @@ pc_patch_uncompressed_deserialize(const SERIALIZED_PATCH *serpatch, const PCSCHE
// }
// SERIALIZED_PATCH;
PCPATCH_UNCOMPRESSED *patch;
uint8_t *buf = (uint8_t*)serpatch->data;
uint8_t *buf;
size_t stats_size = 3*schema->size; // 3 pcpoints worth of stats
/* Reference the external data */
patch = pcalloc(sizeof(PCPATCH_UNCOMPRESSED));
/* Advance data pointer past the stats serialization */
patch->data = buf + stats_size;
/* Calculate the point data buffer size */
patch->datasize = VARSIZE(serpatch) - sizeof(SERIALIZED_PATCH) + 1 - stats_size;
/* Point into the stats area */
patch->stats = pc_patch_stats_deserialize(schema, serpatch->data);
PCPATCH_UNCOMPRESSED *patch = pcalloc(sizeof(PCPATCH_UNCOMPRESSED));
/* Set up basic info */
patch->type = serpatch->compression;
@ -774,6 +759,17 @@ pc_patch_uncompressed_deserialize(const SERIALIZED_PATCH *serpatch, const PCSCHE
patch->maxpoints = 0;
patch->bounds = serpatch->bounds;
buf = (uint8_t*)serpatch->data;
/* Point into the stats area */
patch->stats = pc_patch_stats_deserialize(schema, buf);
/* Advance data pointer past the stats serialization */
patch->data = buf + stats_size;
/* Calculate the point data buffer size */
patch->datasize = VARSIZE(serpatch) - sizeof(SERIALIZED_PATCH) + 1 - stats_size;
return (PCPATCH*)patch;
}

View File

@ -29,6 +29,10 @@
#define PG_GETHEADER_SERPATCH_P(argnum) (SERIALIZED_PATCH*)PG_DETOAST_DATUM_SLICE(PG_GETARG_DATUM(argnum), 0, sizeof(SERIALIZED_PATCH))
#define PG_GETHEADERX_SERPATCH_P(argnum, extra) (SERIALIZED_PATCH*)PG_DETOAST_DATUM_SLICE(PG_GETARG_DATUM(argnum), 0, sizeof(SERIALIZED_PATCH)+extra)
#define PG_GETHEADER_STATS_P(argnum, statsize) (uint8_t*)(((SERIALIZED_PATCH*)PG_DETOAST_DATUM_SLICE(PG_GETARG_DATUM(argnum), 0, sizeof(SERIALIZED_PATCH) + statsize))->data)
#define AUTOCOMPRESS_NO 0
#define AUTOCOMPRESS_YES 1
@ -113,4 +117,6 @@ char* pc_patch_to_hexwkb(const PCPATCH *patch);
uint8_t* pc_patch_to_geometry_wkb_envelope(const SERIALIZED_PATCH *pa, const PCSCHEMA *schema, size_t *wkbsize);
/** Read the first few bytes off an object to get the datum */
uint32 pcid_from_datum(Datum d);
uint32 pcid_from_datum(Datum d);
PCSTATS* pc_patch_stats_deserialize(const PCSCHEMA *schema, const uint8_t *buf);

View File

@ -284,22 +284,16 @@ CREATE OR REPLACE FUNCTION PC_Explode(p pcpatch)
-- SQL Utility Functions
-------------------------------------------------------------------
-- Utility to get AVERAGE value from patch
CREATE OR REPLACE FUNCTION PC_PatchAvg(p pcpatch, attr text)
RETURNS numeric AS
'WITH pts AS ( SELECT PC_Explode($1) AS pt) SELECT avg(PC_Get(pt, $2)) FROM pts'
LANGUAGE 'sql';
-- Utility to get MAXIMUM value from patch
CREATE OR REPLACE FUNCTION PC_PatchMax(p pcpatch, attr text)
RETURNS numeric AS
'WITH pts AS ( SELECT PC_Explode($1) AS pt) SELECT max(PC_Get(pt, $2)) FROM pts'
LANGUAGE 'sql';
CREATE OR REPLACE FUNCTION PC_PatchMax(p pcpatch, attr text, stat text default 'max')
RETURNS numeric AS 'MODULE_PATHNAME', 'pcpatch_get_stat'
LANGUAGE 'c' IMMUTABLE STRICT;
-- Utility to get MINIMUM value from patch
CREATE OR REPLACE FUNCTION PC_PatchMin(p pcpatch, attr text)
RETURNS numeric AS
'WITH pts AS ( SELECT PC_Explode($1) AS pt) SELECT min(PC_Get(pt, $2)) FROM pts'
LANGUAGE 'sql';
CREATE OR REPLACE FUNCTION PC_PatchMin(p pcpatch, attr text, stat text default 'min')
RETURNS numeric AS 'MODULE_PATHNAME', 'pcpatch_get_stat'
LANGUAGE 'c' IMMUTABLE STRICT;
CREATE OR REPLACE FUNCTION PC_PatchAvg(p pcpatch, attr text, stat text default 'avg')
RETURNS numeric AS 'MODULE_PATHNAME', 'pcpatch_get_stat'
LANGUAGE 'c' IMMUTABLE STRICT;